Add readine-like behaviour for \x17, \x04 in input layer.
[screen-lua.git] / src / display.c
blob493c7b0c1800ba7fb2f2ce12849c4e7c83754605
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;
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 return;
637 fcv = 0;
638 if (focusminwidth || focusminheight)
640 debug("searching for focus canvas\n");
641 cv2 = D_forecv;
642 while (cv2->c_slback)
644 if (cv2->c_slback == cv->c_slback)
646 fcv = cv2;
647 focusmin = cv->c_slorient == SLICE_VERT ? focusminheight : focusminwidth;
648 if (focusmin > 0)
649 focusmin--;
650 else if (focusmin < 0)
651 focusmin = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
652 debug1("found, focusmin=%d\n", focusmin);
654 cv2 = cv2->c_slback;
657 if (focusmin)
659 m = CountCanvas(cv) * 2;
660 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
661 nh -= m;
662 if (nh < 0)
663 nh = 0;
664 if (focusmin > nh)
665 focusmin = nh;
666 debug1("corrected to %d\n", focusmin);
669 /* pass 1: calculate weight sum */
670 for (cv2 = cv, wsum = 0; cv2; cv2 = cv2->c_slnext)
672 debug1(" weight %d\n", cv2->c_slweight);
673 wsum += cv2->c_slweight;
675 debug1("wsum = %d\n", wsum);
676 if (wsum == 0)
677 wsum = 1;
678 w = wsum;
680 /* pass 2: calculate need/excess space */
681 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
682 for (cv2 = cv, need = got = 0; cv2; cv2 = cv2->c_slnext)
684 m = cv2->c_slperp ? CountCanvasPerp(cv2) * 2 - 1 : 1;
685 if (cv2 == fcv)
686 m += focusmin;
687 hh = cv2->c_slweight ? nh * cv2->c_slweight / w : 0;
688 w -= cv2->c_slweight;
689 nh -= hh;
690 debug2(" should %d min %d\n", hh, m);
691 if (hh <= m + 1)
692 need += m + 1 - hh;
693 else
694 got += hh - m - 1;
696 debug2("need: %d, got %d\n", need, got);
697 if (need > got)
698 need = got;
700 /* pass 3: distribute space */
701 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
702 i = cv->c_slorient == SLICE_VERT ? ys : xs;
703 maxi = cv->c_slorient == SLICE_VERT ? ye : xe;
704 w = wsum;
705 for (; cv; cv = cvn)
707 cvn = cv->c_slnext;
708 if (i > maxi)
710 if (cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slprev->c_slperp && !cv->c_slprev->c_slprev)
712 cv->c_slprev->c_slorient = SLICE_UNKN;
713 if (!captionalways)
715 cv->c_slback->c_ye++;
716 cv->c_slprev->c_ye++;
719 SetCanvasWindow(cv, 0);
720 FreeCanvas(cv);
721 continue;
723 m = cv->c_slperp ? CountCanvasPerp(cv) * 2 - 1 : 1;
724 if (cv == fcv)
725 m += focusmin;
726 hh = cv->c_slweight ? nh * cv->c_slweight / w : 0;
727 w -= cv->c_slweight;
728 nh -= hh;
729 debug2(" should %d min %d\n", hh, m);
730 if (hh <= m + 1)
732 hh = m + 1;
733 debug1(" -> %d\n", hh);
735 else
737 int hx = need * (hh - m - 1) / got;
738 debug3(" -> %d - %d = %d\n", hh, hx, hh - hx);
739 got -= (hh - m - 1);
740 hh -= hx;
741 need -= hx;
742 debug2(" now need=%d got=%d\n", need, got);
744 ASSERT(hh >= m + 1);
745 /* hh is window size plus pation line */
746 if (i + hh > maxi + 2)
748 hh = maxi + 2 - i;
749 debug1(" not enough space, reducing to %d\n", hh);
751 if (i + hh == maxi + 1)
753 hh++;
754 debug(" incrementing as no other canvas will fit\n");
756 if (cv->c_slorient == SLICE_VERT)
758 cv->c_xs = xs;
759 cv->c_xe = xe;
760 cv->c_ys = i;
761 cv->c_ye = i + hh - 2;
762 cv->c_xoff = xs;
763 cv->c_yoff = i;
765 else
767 cv->c_xs = i;
768 cv->c_xe = i + hh - 2;
769 cv->c_ys = ys;
770 cv->c_ye = ye;
771 cv->c_xoff = i;
772 cv->c_yoff = ys;
774 cv->c_xoff = cv->c_xs;
775 cv->c_yoff = cv->c_ys;
776 if (cv->c_slperp)
778 ResizeCanvas(cv);
779 if (!cv->c_slperp->c_slnext)
781 debug("deleting perp node\n");
782 FreePerp(cv->c_slperp);
783 FreePerp(cv);
786 i += hh;
790 static struct canvas *
791 AddPerp(cv)
792 struct canvas *cv;
794 struct canvas *pcv;
795 debug("Creating new perp node\n");
796 if ((pcv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
797 return 0;
798 pcv->c_next = 0;
799 pcv->c_display = cv->c_display;
800 pcv->c_slnext = cv->c_slnext;
801 pcv->c_slprev = cv->c_slprev;
802 pcv->c_slperp = cv;
803 pcv->c_slback = cv->c_slback;
804 if (cv->c_slback && cv->c_slback->c_slperp == cv)
805 cv->c_slback->c_slperp = pcv;
806 pcv->c_slorient = cv->c_slorient;
807 pcv->c_xoff = 0;
808 pcv->c_yoff = 0;
809 pcv->c_xs = cv->c_xs;
810 pcv->c_xe = cv->c_xe;
811 pcv->c_ys = cv->c_ys;
812 pcv->c_ye = cv->c_ye;
813 if (pcv->c_slnext)
814 pcv->c_slnext->c_slprev = pcv;
815 if (pcv->c_slprev)
816 pcv->c_slprev->c_slnext = pcv;
817 pcv->c_slweight = cv->c_slweight;
818 cv->c_slweight = 1;
819 cv->c_slnext = 0;
820 cv->c_slprev = 0;
821 cv->c_slperp = 0;
822 cv->c_slback = pcv;
823 cv->c_slorient = SLICE_UNKN;
824 return pcv;
827 static void
828 FreePerp(pcv)
829 struct canvas *pcv;
831 struct canvas *cv;
833 if (!pcv->c_slperp)
834 return;
835 cv = pcv->c_slperp;
836 cv->c_slprev = pcv->c_slprev;
837 if (cv->c_slprev)
838 cv->c_slprev->c_slnext = cv;
839 cv->c_slback = pcv->c_slback;
840 if (cv->c_slback && cv->c_slback->c_slperp == pcv)
841 cv->c_slback->c_slperp = cv;
842 cv->c_slorient = pcv->c_slorient;
843 cv->c_slweight = pcv->c_slweight;
844 while (cv->c_slnext)
846 cv = cv->c_slnext;
847 cv->c_slorient = pcv->c_slorient;
848 cv->c_slback = pcv->c_slback;
849 cv->c_slweight = pcv->c_slweight;
851 cv->c_slnext = pcv->c_slnext;
852 if (cv->c_slnext)
853 cv->c_slnext->c_slprev = cv;
854 free(pcv);
858 AddCanvas(orient)
859 int orient;
861 struct canvas *cv;
862 int xs, xe, ys, ye;
863 int h, num;
865 cv = D_forecv;
866 debug2("AddCanvas orient %d, forecv is %d\n", orient, cv->c_slorient);
868 if (cv->c_slorient != SLICE_UNKN && cv->c_slorient != orient)
869 if (!AddPerp(cv))
870 return -1;
872 cv = D_forecv;
873 xs = cv->c_slback->c_xs;
874 xe = cv->c_slback->c_xe;
875 ys = cv->c_slback->c_ys;
876 ye = cv->c_slback->c_ye;
877 if (!captionalways && cv == D_canvas.c_slperp && !cv->c_slnext)
878 ye--; /* need space for caption */
879 debug2("Adding Canvas to slice %d,%d ", xs, ys);
880 debug2("%d,%d\n", xe, ye);
882 num = CountCanvas(cv->c_slback->c_slperp) + 1;
883 debug1("Num = %d\n", num);
884 if (orient == SLICE_VERT)
885 h = ye - ys + 1;
886 else
887 h = xe - xs + 1;
889 h -= 2 * num - 1;
890 if (h < 0)
891 return -1; /* can't fit in */
893 if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
894 return -1;
896 D_forecv->c_slback->c_ye = ye; /* in case we modified it above */
897 D_forecv->c_slorient = orient; /* in case it was UNKN */
898 cv->c_slnext = D_forecv->c_slnext;
899 cv->c_slprev = D_forecv;
900 D_forecv->c_slnext = cv;
901 if (cv->c_slnext)
902 cv->c_slnext->c_slprev = cv;
903 cv->c_slorient = orient;
904 cv->c_slback = D_forecv->c_slback;
906 cv->c_xs = xs;
907 cv->c_xe = xe;
908 cv->c_ys = ys;
909 cv->c_ye = ye;
910 cv->c_xoff = 0;
911 cv->c_yoff = 0;
912 cv->c_display = display;
913 cv->c_vplist = 0;
914 cv->c_captev.type = EV_TIMEOUT;
915 cv->c_captev.data = (char *)cv;
916 cv->c_captev.handler = cv_winid_fn;
918 cv->c_blank.l_cvlist = cv;
919 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
920 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
921 cv->c_blank.l_x = cv->c_blank.l_y = 0;
922 cv->c_blank.l_layfn = &BlankLf;
923 cv->c_blank.l_data = 0;
924 cv->c_blank.l_next = 0;
925 cv->c_blank.l_bottom = &cv->c_blank;
926 cv->c_blank.l_blocking = 0;
927 cv->c_layer = &cv->c_blank;
928 cv->c_lnext = 0;
930 cv->c_next = 0;
932 cv = cv->c_slback;
933 EqualizeCanvas(cv->c_slperp, 0);
934 ResizeCanvas(cv);
935 RecreateCanvasChain();
936 RethinkDisplayViewports();
937 ResizeLayersToCanvases();
938 return 0;
941 void
942 RemCanvas()
944 int xs, xe, ys, ye;
945 struct canvas *cv;
947 debug("RemCanvas\n");
948 cv = D_forecv;
949 if (cv->c_slorient == SLICE_UNKN)
950 return;
951 while (cv->c_slprev)
952 cv = cv->c_slprev;
953 if (!cv->c_slnext)
954 return;
955 if (!cv->c_slnext->c_slnext && cv->c_slback->c_slback)
957 /* two canvases in slice, kill perp node */
958 cv = D_forecv;
959 debug("deleting perp node\n");
960 FreePerp(cv->c_slprev ? cv->c_slprev : cv->c_slnext);
961 FreePerp(cv->c_slback);
963 xs = cv->c_slback->c_xs;
964 xe = cv->c_slback->c_xe;
965 ys = cv->c_slback->c_ys;
966 ye = cv->c_slback->c_ye;
967 /* free canvas */
968 cv = D_forecv;
969 D_forecv = cv->c_slprev;
970 if (!D_forecv)
971 D_forecv = cv->c_slnext;
972 FreeCanvas(cv);
974 cv = D_forecv;
975 while (D_forecv->c_slperp)
976 D_forecv = D_forecv->c_slperp;
978 /* if only one canvas left, set orient back to unknown */
979 if (!cv->c_slnext && !cv->c_slprev && !cv->c_slback->c_slback)
981 cv->c_slorient = SLICE_UNKN;
982 if (!captionalways)
983 cv->c_slback->c_ye = ++ye; /* caption line no longer needed */
985 cv = cv->c_slback;
986 EqualizeCanvas(cv->c_slperp, 0);
987 ResizeCanvas(cv);
989 D_fore = Layer2Window(D_forecv->c_layer);
990 flayer = D_forecv->c_layer;
992 RecreateCanvasChain();
993 RethinkDisplayViewports();
994 ResizeLayersToCanvases();
997 void
998 OneCanvas()
1000 struct canvas *cv = D_forecv, *ocv = 0;
1002 if (cv->c_slprev)
1004 ocv = cv->c_slprev;
1005 cv->c_slprev->c_slnext = cv->c_slnext;
1007 if (cv->c_slnext)
1009 ocv = cv->c_slnext;
1010 cv->c_slnext->c_slprev = cv->c_slprev;
1012 if (!ocv)
1013 return;
1014 if (cv->c_slback && cv->c_slback->c_slperp == cv)
1015 cv->c_slback->c_slperp = ocv;
1016 cv->c_slorient = SLICE_UNKN;
1017 while (D_canvas.c_slperp)
1018 FreeCanvas(D_canvas.c_slperp);
1019 cv = D_forecv;
1020 D_canvas.c_slperp = cv;
1021 cv->c_slback = &D_canvas;
1022 cv->c_slnext = 0;
1023 cv->c_slprev = 0;
1024 ASSERT(!cv->c_slperp);
1025 if (!captionalways)
1026 D_canvas.c_ye++; /* caption line no longer needed */
1027 ResizeCanvas(&D_canvas);
1028 RecreateCanvasChain();
1029 RethinkDisplayViewports();
1030 ResizeLayersToCanvases();
1034 RethinkDisplayViewports()
1036 struct canvas *cv;
1037 struct viewport *vp, *vpn;
1039 /* free old viewports */
1040 for (cv = display->d_cvlist; cv; cv = cv->c_next)
1042 for (vp = cv->c_vplist; vp; vp = vpn)
1044 vp->v_canvas = 0;
1045 vpn = vp->v_next;
1046 bzero((char *)vp, sizeof(*vp));
1047 free(vp);
1049 cv->c_vplist = 0;
1051 display->d_vpxmin = -1;
1052 display->d_vpxmax = -1;
1054 for (cv = display->d_cvlist; cv; cv = cv->c_next)
1056 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1057 return -1;
1058 #ifdef HOLE
1059 vp->v_canvas = cv;
1060 vp->v_xs = cv->c_xs;
1061 vp->v_ys = (cv->c_ys + cv->c_ye) / 2;
1062 vp->v_xe = cv->c_xe;
1063 vp->v_ye = cv->c_ye;
1064 vp->v_xoff = cv->c_xoff;
1065 vp->v_yoff = cv->c_yoff;
1066 vp->v_next = cv->c_vplist;
1067 cv->c_vplist = vp;
1069 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1070 return -1;
1071 vp->v_canvas = cv;
1072 vp->v_xs = (cv->c_xs + cv->c_xe) / 2;
1073 vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
1074 vp->v_xe = cv->c_xe;
1075 vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
1076 vp->v_xoff = cv->c_xoff;
1077 vp->v_yoff = cv->c_yoff;
1078 vp->v_next = cv->c_vplist;
1079 cv->c_vplist = vp;
1081 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1082 return -1;
1083 vp->v_canvas = cv;
1084 vp->v_xs = cv->c_xs;
1085 vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
1086 vp->v_xe = (3 * cv->c_xs + cv->c_xe) / 4 - 1;
1087 vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
1088 vp->v_xoff = cv->c_xoff;
1089 vp->v_yoff = cv->c_yoff;
1090 vp->v_next = cv->c_vplist;
1091 cv->c_vplist = vp;
1093 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1094 return -1;
1095 vp->v_canvas = cv;
1096 vp->v_xs = cv->c_xs;
1097 vp->v_ys = cv->c_ys;
1098 vp->v_xe = cv->c_xe;
1099 vp->v_ye = (3 * cv->c_ys + cv->c_ye) / 4 - 1;
1100 vp->v_xoff = cv->c_xoff;
1101 vp->v_yoff = cv->c_yoff;
1102 vp->v_next = cv->c_vplist;
1103 cv->c_vplist = vp;
1104 #else
1105 vp->v_canvas = cv;
1106 vp->v_xs = cv->c_xs;
1107 vp->v_ys = cv->c_ys;
1108 vp->v_xe = cv->c_xe;
1109 vp->v_ye = cv->c_ye;
1110 vp->v_xoff = cv->c_xoff;
1111 vp->v_yoff = cv->c_yoff;
1112 vp->v_next = cv->c_vplist;
1113 cv->c_vplist = vp;
1114 #endif
1116 if (cv->c_xs < display->d_vpxmin || display->d_vpxmin == -1)
1117 display->d_vpxmin = cv->c_xs;
1118 if (cv->c_xe > display->d_vpxmax || display->d_vpxmax == -1)
1119 display->d_vpxmax = cv->c_xe;
1121 return 0;
1124 void
1125 RethinkViewportOffsets(cv)
1126 struct canvas *cv;
1128 struct viewport *vp;
1130 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1132 vp->v_xoff = cv->c_xoff;
1133 vp->v_yoff = cv->c_yoff;
1138 * if the adaptflag is on, we keep the size of this display, else
1139 * we may try to restore our old window sizes.
1141 void
1142 InitTerm(adapt)
1143 int adapt;
1145 ASSERT(display);
1146 ASSERT(D_tcinited);
1147 D_top = D_bot = -1;
1148 AddCStr(D_TI);
1149 AddCStr(D_IS);
1150 /* Check for toggle */
1151 if (D_IM && strcmp(D_IM, D_EI))
1152 AddCStr(D_EI);
1153 D_insert = 0;
1154 #ifdef MAPKEYS
1155 AddCStr(D_KS);
1156 AddCStr(D_CCS);
1157 #else
1158 /* Check for toggle */
1159 if (D_KS && strcmp(D_KS, D_KE))
1160 AddCStr(D_KE);
1161 if (D_CCS && strcmp(D_CCS, D_CCE))
1162 AddCStr(D_CCE);
1163 #endif
1164 D_keypad = 0;
1165 D_cursorkeys = 0;
1166 AddCStr(D_ME);
1167 AddCStr(D_EA);
1168 AddCStr(D_CE0);
1169 D_rend = mchar_null;
1170 D_atyp = 0;
1171 if (adapt == 0)
1172 ResizeDisplay(D_defwidth, D_defheight);
1173 ChangeScrollRegion(0, D_height - 1);
1174 D_x = D_y = 0;
1175 Flush();
1176 ClearAll();
1177 debug1("we %swant to adapt all our windows to the display\n",
1178 (adapt) ? "" : "don't ");
1179 /* In case the size was changed by a init sequence */
1180 CheckScreenSize((adapt) ? 2 : 0);
1183 void
1184 FinitTerm()
1186 ASSERT(display);
1187 #ifdef BLANKER_PRG
1188 KillBlanker();
1189 #endif
1190 if (D_tcinited)
1192 ResizeDisplay(D_defwidth, D_defheight);
1193 InsertMode(0);
1194 ChangeScrollRegion(0, D_height - 1);
1195 KeypadMode(0);
1196 CursorkeysMode(0);
1197 CursorVisibility(0);
1198 MouseMode(0);
1199 SetRendition(&mchar_null);
1200 SetFlow(FLOW_NOW);
1201 #ifdef MAPKEYS
1202 AddCStr(D_KE);
1203 AddCStr(D_CCE);
1204 #endif
1205 if (D_hstatus)
1206 ShowHStatus((char *)0);
1207 #ifdef RXVT_OSC
1208 ClearAllXtermOSC();
1209 #endif
1210 D_x = D_y = -1;
1211 GotoPos(0, D_height - 1);
1212 AddChar('\r');
1213 AddChar('\n');
1214 AddCStr(D_TE);
1216 Flush();
1220 static void
1221 INSERTCHAR(c)
1222 int c;
1224 ASSERT(display);
1225 if (!D_insert && D_x < D_width - 1)
1227 if (D_IC || D_CIC)
1229 if (D_IC)
1230 AddCStr(D_IC);
1231 else
1232 AddCStr2(D_CIC, 1);
1233 RAW_PUTCHAR(c);
1234 return;
1236 InsertMode(1);
1237 if (!D_insert)
1239 RefreshLine(D_y, D_x, D_width-1, 0);
1240 return;
1243 RAW_PUTCHAR(c);
1246 void
1247 PUTCHAR(c)
1248 int c;
1250 ASSERT(display);
1251 if (D_insert && D_x < D_width - 1)
1252 InsertMode(0);
1253 RAW_PUTCHAR(c);
1256 void
1257 PUTCHARLP(c)
1258 int c;
1260 if (D_x < D_width - 1)
1262 if (D_insert)
1263 InsertMode(0);
1264 RAW_PUTCHAR(c);
1265 return;
1267 if (D_CLP || D_y != D_bot)
1269 int y = D_y;
1270 RAW_PUTCHAR(c);
1271 if (D_AM && !D_CLP)
1272 GotoPos(D_width - 1, y);
1273 return;
1275 debug("PUTCHARLP: lp_missing!\n");
1276 D_lp_missing = 1;
1277 D_rend.image = c;
1278 D_lpchar = D_rend;
1279 #ifdef DW_CHARS
1280 /* XXX -> PutChar ? */
1281 if (D_mbcs)
1283 D_lpchar.mbcs = c;
1284 D_lpchar.image = D_mbcs;
1285 D_mbcs = 0;
1286 D_x--;
1288 #endif
1292 * RAW_PUTCHAR() is for all text that will be displayed.
1293 * NOTE: charset Nr. 0 has a conversion table, but c1, c2, ... don't.
1296 STATIC void
1297 RAW_PUTCHAR(c)
1298 int c;
1300 ASSERT(display);
1302 #ifdef FONT
1303 # ifdef UTF8
1304 if (D_encoding == UTF8)
1306 c = (c & 255) | (unsigned char)D_rend.font << 8;
1307 # ifdef DW_CHARS
1308 if (D_mbcs)
1310 c = D_mbcs;
1311 if (D_x == D_width)
1312 D_x += D_AM ? 1 : -1;
1313 D_mbcs = 0;
1315 else if (utf8_isdouble(c))
1317 D_mbcs = c;
1318 D_x++;
1319 return;
1321 # endif
1322 if (c < 32)
1324 AddCStr2(D_CS0, '0');
1325 AddChar(c + 0x5f);
1326 AddCStr(D_CE0);
1327 goto addedutf8;
1329 AddUtf8(c);
1330 goto addedutf8;
1332 # endif
1333 # ifdef DW_CHARS
1334 if (is_dw_font(D_rend.font))
1336 int t = c;
1337 if (D_mbcs == 0)
1339 D_mbcs = c;
1340 D_x++;
1341 return;
1343 D_x--;
1344 if (D_x == D_width - 1)
1345 D_x += D_AM ? 1 : -1;
1346 c = D_mbcs;
1347 D_mbcs = t;
1349 # endif
1350 # if defined(ENCODINGS) && defined(DW_CHARS)
1351 if (D_encoding)
1352 c = PrepareEncodedChar(c);
1353 # endif
1354 # ifdef DW_CHARS
1355 kanjiloop:
1356 # endif
1357 if (D_xtable && D_xtable[(int)(unsigned char)D_rend.font] && D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c])
1358 AddStr(D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c]);
1359 else
1360 AddChar(D_rend.font != '0' ? c : D_c0_tab[(int)(unsigned char)c]);
1361 #else /* FONT */
1362 AddChar(c);
1363 #endif /* FONT */
1365 #ifdef UTF8
1366 addedutf8:
1367 #endif
1368 if (++D_x >= D_width)
1370 if (D_AM == 0)
1371 D_x = D_width - 1;
1372 else if (!D_CLP || D_x > D_width)
1374 D_x -= D_width;
1375 if (D_y < D_height-1 && D_y != D_bot)
1376 D_y++;
1379 #ifdef DW_CHARS
1380 if (D_mbcs)
1382 c = D_mbcs;
1383 D_mbcs = 0;
1384 goto kanjiloop;
1386 #endif
1389 static int
1390 DoAddChar(c)
1391 int c;
1393 /* this is for ESC-sequences only (AddChar is a macro) */
1394 AddChar(c);
1395 return c;
1398 void
1399 AddCStr(s)
1400 char *s;
1402 if (display && s && *s)
1404 ospeed = D_dospeed;
1405 tputs(s, 1, DoAddChar);
1409 void
1410 AddCStr2(s, c)
1411 char *s;
1412 int c;
1414 if (display && s && *s)
1416 ospeed = D_dospeed;
1417 tputs(tgoto(s, 0, c), 1, DoAddChar);
1422 /* Insert mode is a toggle on some terminals, so we need this hack:
1424 void
1425 InsertMode(on)
1426 int on;
1428 if (display && on != D_insert && D_IM)
1430 D_insert = on;
1431 if (on)
1432 AddCStr(D_IM);
1433 else
1434 AddCStr(D_EI);
1438 /* ...and maybe keypad application mode is a toggle, too:
1440 void
1441 KeypadMode(on)
1442 int on;
1444 #ifdef MAPKEYS
1445 if (display)
1446 D_keypad = on;
1447 #else
1448 if (display && D_keypad != on && D_KS)
1450 D_keypad = on;
1451 if (on)
1452 AddCStr(D_KS);
1453 else
1454 AddCStr(D_KE);
1456 #endif
1459 void
1460 CursorkeysMode(on)
1461 int on;
1463 #ifdef MAPKEYS
1464 if (display)
1465 D_cursorkeys = on;
1466 #else
1467 if (display && D_cursorkeys != on && D_CCS)
1469 D_cursorkeys = on;
1470 if (on)
1471 AddCStr(D_CCS);
1472 else
1473 AddCStr(D_CCE);
1475 #endif
1478 void
1479 ReverseVideo(on)
1480 int on;
1482 if (display && D_revvid != on && D_CVR)
1484 D_revvid = on;
1485 if (D_revvid)
1486 AddCStr(D_CVR);
1487 else
1488 AddCStr(D_CVN);
1492 void
1493 CursorVisibility(v)
1494 int v;
1496 if (display && D_curvis != v)
1498 if (D_curvis)
1499 AddCStr(D_VE); /* do this always, just to be safe */
1500 D_curvis = 0;
1501 if (v == -1 && D_VI)
1502 AddCStr(D_VI);
1503 else if (v == 1 && D_VS)
1504 AddCStr(D_VS);
1505 else
1506 return;
1507 D_curvis = v;
1511 void
1512 MouseMode(mode)
1513 int mode;
1515 if (display && D_mouse != mode)
1517 char mousebuf[20];
1518 if (!D_CXT)
1519 return;
1520 if (D_mouse)
1522 sprintf(mousebuf, "\033[?%dl", D_mouse);
1523 AddStr(mousebuf);
1525 if (mode)
1527 sprintf(mousebuf, "\033[?%dh", mode);
1528 AddStr(mousebuf);
1530 D_mouse = mode;
1534 static int StrCost;
1536 /* ARGSUSED */
1537 static int
1538 CountChars(c)
1539 int c;
1541 StrCost++;
1542 return c;
1546 CalcCost(s)
1547 register char *s;
1549 ASSERT(display);
1550 if (s)
1552 StrCost = 0;
1553 ospeed = D_dospeed;
1554 tputs(s, 1, CountChars);
1555 return StrCost;
1557 else
1558 return EXPENSIVE;
1561 static int
1562 CallRewrite(y, xs, xe, doit)
1563 int y, xs, xe, doit;
1565 struct canvas *cv, *cvlist, *cvlnext;
1566 struct viewport *vp;
1567 struct layer *oldflayer;
1568 int cost;
1570 debug3("CallRewrite %d %d %d\n", y, xs, xe);
1571 ASSERT(display);
1572 ASSERT(xe >= xs);
1574 vp = 0;
1575 for (cv = D_cvlist; cv; cv = cv->c_next)
1577 if (y < cv->c_ys || y > cv->c_ye || xe < cv->c_xs || xs > cv->c_xe)
1578 continue;
1579 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1580 if (y >= vp->v_ys && y <= vp->v_ye && xe >= vp->v_xs && xs <= vp->v_xe)
1581 break;
1582 if (vp)
1583 break;
1585 if (doit)
1587 oldflayer = flayer;
1588 flayer = cv->c_layer;
1589 cvlist = flayer->l_cvlist;
1590 cvlnext = cv->c_lnext;
1591 flayer->l_cvlist = cv;
1592 cv->c_lnext = 0;
1593 LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 1);
1594 flayer->l_cvlist = cvlist;
1595 cv->c_lnext = cvlnext;
1596 flayer = oldflayer;
1597 return 0;
1599 if (cv == 0 || cv->c_layer == 0)
1600 return EXPENSIVE; /* not found or nothing on it */
1601 if (xs < vp->v_xs || xe > vp->v_xe)
1602 return EXPENSIVE; /* crosses viewport boundaries */
1603 if (y - vp->v_yoff < 0 || y - vp->v_yoff >= cv->c_layer->l_height)
1604 return EXPENSIVE; /* line not on layer */
1605 if (xs - vp->v_xoff < 0 || xe - vp->v_xoff >= cv->c_layer->l_width)
1606 return EXPENSIVE; /* line not on layer */
1607 #ifdef UTF8
1608 if (D_encoding == UTF8)
1609 D_rend.font = 0;
1610 #endif
1611 oldflayer = flayer;
1612 flayer = cv->c_layer;
1613 debug3("Calling Rewrite %d %d %d\n", y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff);
1614 cost = LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 0);
1615 flayer = oldflayer;
1616 if (D_insert)
1617 cost += D_EIcost + D_IMcost;
1618 return cost;
1622 void
1623 GotoPos(x2, y2)
1624 int x2, y2;
1626 register int dy, dx, x1, y1;
1627 register int costx, costy;
1628 register int m;
1629 register char *s;
1630 int CMcost;
1631 enum move_t xm = M_NONE, ym = M_NONE;
1633 if (!display)
1634 return;
1636 x1 = D_x;
1637 y1 = D_y;
1639 if (x1 == D_width)
1641 if (D_CLP && D_AM)
1642 x1 = -1; /* don't know how the terminal treats this */
1643 else
1644 x1--;
1646 if (x2 == D_width)
1647 x2--;
1648 dx = x2 - x1;
1649 dy = y2 - y1;
1650 if (dy == 0 && dx == 0)
1651 return;
1652 debug2("GotoPos (%d,%d)", x1, y1);
1653 debug2(" -> (%d,%d)\n", x2, y2);
1654 if (!D_MS) /* Safe to move ? */
1655 SetRendition(&mchar_null);
1656 if (y1 < 0 /* don't know the y position */
1657 || (y2 > D_bot && y1 <= D_bot) /* have to cross border */
1658 || (y2 < D_top && y1 >= D_top)) /* of scrollregion ? */
1660 DoCM:
1661 if (D_HO && !x2 && !y2)
1662 AddCStr(D_HO);
1663 else
1664 AddCStr(tgoto(D_CM, x2, y2));
1665 D_x = x2;
1666 D_y = y2;
1667 return;
1670 /* some scrollregion implementations don't allow movements
1671 * away from the region. sigh.
1673 if ((y1 > D_bot && y2 > y1) || (y1 < D_top && y2 < y1))
1674 goto DoCM;
1676 /* Calculate CMcost */
1677 if (D_HO && !x2 && !y2)
1678 s = D_HO;
1679 else
1680 s = tgoto(D_CM, x2, y2);
1681 CMcost = CalcCost(s);
1683 /* Calculate the cost to move the cursor to the right x position */
1684 costx = EXPENSIVE;
1685 if (x1 >= 0) /* relativ x positioning only if we know where we are */
1687 if (dx > 0)
1689 if (D_CRI && (dx > 1 || !D_ND))
1691 costx = CalcCost(tgoto(D_CRI, 0, dx));
1692 xm = M_CRI;
1694 if ((m = D_NDcost * dx) < costx)
1696 costx = m;
1697 xm = M_RI;
1699 /* Speedup: dx <= LayRewrite() */
1700 if (dx < costx && (m = CallRewrite(y1, x1, x2 - 1, 0)) < costx)
1702 costx = m;
1703 xm = M_RW;
1706 else if (dx < 0)
1708 if (D_CLE && (dx < -1 || !D_BC))
1710 costx = CalcCost(tgoto(D_CLE, 0, -dx));
1711 xm = M_CLE;
1713 if ((m = -dx * D_LEcost) < costx)
1715 costx = m;
1716 xm = M_LE;
1719 else
1720 costx = 0;
1722 /* Speedup: LayRewrite() >= x2 */
1723 if (x2 + D_CRcost < costx && (m = (x2 ? CallRewrite(y1, 0, x2 - 1, 0) : 0) + D_CRcost) < costx)
1725 costx = m;
1726 xm = M_CR;
1729 /* Check if it is already cheaper to do CM */
1730 if (costx >= CMcost)
1731 goto DoCM;
1733 /* Calculate the cost to move the cursor to the right y position */
1734 costy = EXPENSIVE;
1735 if (dy > 0)
1737 if (D_CDO && dy > 1) /* DO & NL are always != 0 */
1739 costy = CalcCost(tgoto(D_CDO, 0, dy));
1740 ym = M_CDO;
1742 if ((m = dy * ((x2 == 0) ? D_NLcost : D_DOcost)) < costy)
1744 costy = m;
1745 ym = M_DO;
1748 else if (dy < 0)
1750 if (D_CUP && (dy < -1 || !D_UP))
1752 costy = CalcCost(tgoto(D_CUP, 0, -dy));
1753 ym = M_CUP;
1755 if ((m = -dy * D_UPcost) < costy)
1757 costy = m;
1758 ym = M_UP;
1761 else
1762 costy = 0;
1764 /* Finally check if it is cheaper to do CM */
1765 if (costx + costy >= CMcost)
1766 goto DoCM;
1768 switch (xm)
1770 case M_LE:
1771 while (dx++ < 0)
1772 AddCStr(D_BC);
1773 break;
1774 case M_CLE:
1775 AddCStr2(D_CLE, -dx);
1776 break;
1777 case M_RI:
1778 while (dx-- > 0)
1779 AddCStr(D_ND);
1780 break;
1781 case M_CRI:
1782 AddCStr2(D_CRI, dx);
1783 break;
1784 case M_CR:
1785 AddCStr(D_CR);
1786 D_x = 0;
1787 x1 = 0;
1788 /* FALLTHROUGH */
1789 case M_RW:
1790 if (x1 < x2)
1791 (void) CallRewrite(y1, x1, x2 - 1, 1);
1792 break;
1793 default:
1794 break;
1797 switch (ym)
1799 case M_UP:
1800 while (dy++ < 0)
1801 AddCStr(D_UP);
1802 break;
1803 case M_CUP:
1804 AddCStr2(D_CUP, -dy);
1805 break;
1806 case M_DO:
1807 s = (x2 == 0) ? D_NL : D_DO;
1808 while (dy-- > 0)
1809 AddCStr(s);
1810 break;
1811 case M_CDO:
1812 AddCStr2(D_CDO, dy);
1813 break;
1814 default:
1815 break;
1817 D_x = x2;
1818 D_y = y2;
1821 void
1822 ClearAll()
1824 ASSERT(display);
1825 ClearArea(0, 0, 0, D_width - 1, D_width - 1, D_height - 1, 0, 0);
1828 void
1829 ClearArea(x1, y1, xs, xe, x2, y2, bce, uselayfn)
1830 int x1, y1, xs, xe, x2, y2, bce, uselayfn;
1832 int y, xxe;
1833 struct canvas *cv;
1834 struct viewport *vp;
1836 debug2("Clear %d,%d", x1, y1);
1837 debug2(" %d-%d", xs, xe);
1838 debug2(" %d,%d", x2, y2);
1839 debug2(" uselayfn=%d bce=%d\n", uselayfn, bce);
1840 ASSERT(display);
1841 if (x1 == D_width)
1842 x1--;
1843 if (x2 == D_width)
1844 x2--;
1845 if (xs == -1)
1846 xs = x1;
1847 if (xe == -1)
1848 xe = x2;
1849 if (D_UT) /* Safe to erase ? */
1850 SetRendition(&mchar_null);
1851 #ifdef COLOR
1852 if (D_BE)
1853 SetBackColor(bce);
1854 #endif
1855 if (D_lp_missing && y1 <= D_bot && xe >= D_width - 1)
1857 if (y2 > D_bot || (y2 == D_bot && x2 >= D_width - 1))
1858 D_lp_missing = 0;
1860 if (x2 == D_width - 1 && (xs == 0 || y1 == y2) && xe == D_width - 1 && y2 == D_height - 1 && (!bce || D_BE))
1862 #ifdef AUTO_NUKE
1863 if (x1 == 0 && y1 == 0 && D_auto_nuke)
1864 NukePending();
1865 #endif
1866 if (x1 == 0 && y1 == 0 && D_CL)
1868 AddCStr(D_CL);
1869 D_y = D_x = 0;
1870 return;
1873 * Workaround a hp700/22 terminal bug. Do not use CD where CE
1874 * is also appropriate.
1876 if (D_CD && (y1 < y2 || !D_CE))
1878 GotoPos(x1, y1);
1879 AddCStr(D_CD);
1880 return;
1883 if (x1 == 0 && xs == 0 && (xe == D_width - 1 || y1 == y2) && y1 == 0 && D_CCD && (!bce || D_BE))
1885 GotoPos(x1, y1);
1886 AddCStr(D_CCD);
1887 return;
1889 xxe = xe;
1890 for (y = y1; y <= y2; y++, x1 = xs)
1892 if (y == y2)
1893 xxe = x2;
1894 if (x1 == 0 && D_CB && (xxe != D_width - 1 || (D_x == xxe && D_y == y)) && (!bce || D_BE))
1896 GotoPos(xxe, y);
1897 AddCStr(D_CB);
1898 continue;
1900 if (xxe == D_width - 1 && D_CE && (!bce || D_BE))
1902 GotoPos(x1, y);
1903 AddCStr(D_CE);
1904 continue;
1906 if (uselayfn)
1908 vp = 0;
1909 for (cv = D_cvlist; cv; cv = cv->c_next)
1911 if (y < cv->c_ys || y > cv->c_ye || xxe < cv->c_xs || x1 > cv->c_xe)
1912 continue;
1913 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1914 if (y >= vp->v_ys && y <= vp->v_ye && xxe >= vp->v_xs && x1 <= vp->v_xe)
1915 break;
1916 if (vp)
1917 break;
1919 if (cv && cv->c_layer && x1 >= vp->v_xs && xxe <= vp->v_xe &&
1920 y - vp->v_yoff >= 0 && y - vp->v_yoff < cv->c_layer->l_height &&
1921 xxe - vp->v_xoff >= 0 && x1 - vp->v_xoff < cv->c_layer->l_width)
1923 struct layer *oldflayer = flayer;
1924 struct canvas *cvlist, *cvlnext;
1925 flayer = cv->c_layer;
1926 cvlist = flayer->l_cvlist;
1927 cvlnext = cv->c_lnext;
1928 flayer->l_cvlist = cv;
1929 cv->c_lnext = 0;
1930 LayClearLine(y - vp->v_yoff, x1 - vp->v_xoff, xxe - vp->v_xoff, bce);
1931 flayer->l_cvlist = cvlist;
1932 cv->c_lnext = cvlnext;
1933 flayer = oldflayer;
1934 continue;
1937 ClearLine((struct mline *)0, y, x1, xxe, bce);
1943 * if cur_only > 0, we only redisplay current line, as a full refresh is
1944 * too expensive over a low baud line.
1946 void
1947 Redisplay(cur_only)
1948 int cur_only;
1950 ASSERT(display);
1952 /* XXX do em all? */
1953 InsertMode(0);
1954 ChangeScrollRegion(0, D_height - 1);
1955 KeypadMode(0);
1956 CursorkeysMode(0);
1957 CursorVisibility(0);
1958 MouseMode(0);
1959 SetRendition(&mchar_null);
1960 SetFlow(FLOW_NOW);
1962 ClearAll();
1963 #ifdef RXVT_OSC
1964 RefreshXtermOSC();
1965 #endif
1966 if (cur_only > 0 && D_fore)
1967 RefreshArea(0, D_fore->w_y, D_width - 1, D_fore->w_y, 1);
1968 else
1969 RefreshAll(1);
1970 RefreshHStatus();
1971 CV_CALL(D_forecv, LayRestore();LaySetCursor());
1974 void
1975 RedisplayDisplays(cur_only)
1976 int cur_only;
1978 struct display *olddisplay = display;
1979 for (display = displays; display; display = display->d_next)
1980 Redisplay(cur_only);
1981 display = olddisplay;
1985 /* XXX: use oml! */
1986 void
1987 ScrollH(y, xs, xe, n, bce, oml)
1988 int y, xs, xe, n, bce;
1989 struct mline *oml;
1991 int i;
1993 if (n == 0)
1994 return;
1995 if (xe != D_width - 1)
1997 RefreshLine(y, xs, xe, 0);
1998 /* UpdateLine(oml, y, xs, xe); */
1999 return;
2001 GotoPos(xs, y);
2002 if (D_UT)
2003 SetRendition(&mchar_null);
2004 #ifdef COLOR
2005 if (D_BE)
2006 SetBackColor(bce);
2007 #endif
2008 if (n > 0)
2010 if (n >= xe - xs + 1)
2011 n = xe - xs + 1;
2012 if (D_CDC && !(n == 1 && D_DC))
2013 AddCStr2(D_CDC, n);
2014 else if (D_DC)
2016 for (i = n; i--; )
2017 AddCStr(D_DC);
2019 else
2021 RefreshLine(y, xs, xe, 0);
2022 /* UpdateLine(oml, y, xs, xe); */
2023 return;
2026 else
2028 if (-n >= xe - xs + 1)
2029 n = -(xe - xs + 1);
2030 if (!D_insert)
2032 if (D_CIC && !(n == -1 && D_IC))
2033 AddCStr2(D_CIC, -n);
2034 else if (D_IC)
2036 for (i = -n; i--; )
2037 AddCStr(D_IC);
2039 else if (D_IM)
2041 InsertMode(1);
2042 SetRendition(&mchar_null);
2043 #ifdef COLOR
2044 SetBackColor(bce);
2045 #endif
2046 for (i = -n; i--; )
2047 INSERTCHAR(' ');
2048 bce = 0; /* all done */
2050 else
2052 /* UpdateLine(oml, y, xs, xe); */
2053 RefreshLine(y, xs, xe, 0);
2054 return;
2057 else
2059 SetRendition(&mchar_null);
2060 #ifdef COLOR
2061 SetBackColor(bce);
2062 #endif
2063 for (i = -n; i--; )
2064 INSERTCHAR(' ');
2065 bce = 0; /* all done */
2068 if (bce && !D_BE)
2070 if (n > 0)
2071 ClearLine((struct mline *)0, y, xe - n + 1, xe, bce);
2072 else
2073 ClearLine((struct mline *)0, y, xs, xs - n - 1, bce);
2075 if (D_lp_missing && y == D_bot)
2077 if (n > 0)
2078 WriteLP(D_width - 1 - n, y);
2079 D_lp_missing = 0;
2083 void
2084 ScrollV(xs, ys, xe, ye, n, bce)
2085 int xs, ys, xe, ye, n, bce;
2087 int i;
2088 int up;
2089 int oldtop, oldbot;
2090 int alok, dlok, aldlfaster;
2091 int missy = 0;
2093 ASSERT(display);
2094 if (n == 0)
2095 return;
2096 if (n >= ye - ys + 1 || -n >= ye - ys + 1)
2098 ClearArea(xs, ys, xs, xe, xe, ye, bce, 0);
2099 return;
2101 if (xs > D_vpxmin || xe < D_vpxmax)
2103 RefreshArea(xs, ys, xe, ye, 0);
2104 return;
2107 if (D_lp_missing)
2109 if (D_bot > ye || D_bot < ys)
2110 missy = D_bot;
2111 else
2113 missy = D_bot - n;
2114 if (missy > ye || missy < ys)
2115 D_lp_missing = 0;
2119 up = 1;
2120 if (n < 0)
2122 up = 0;
2123 n = -n;
2125 if (n >= ye - ys + 1)
2126 n = ye - ys + 1;
2128 oldtop = D_top;
2129 oldbot = D_bot;
2130 if (ys < D_top || D_bot != ye)
2131 ChangeScrollRegion(ys, ye);
2132 alok = (D_AL || D_CAL || (ys >= D_top && ye == D_bot && up));
2133 dlok = (D_DL || D_CDL || (ys >= D_top && ye == D_bot && !up));
2134 if (D_top != ys && !(alok && dlok))
2135 ChangeScrollRegion(ys, ye);
2137 if (D_lp_missing &&
2138 (oldbot != D_bot ||
2139 (oldbot == D_bot && up && D_top == ys && D_bot == ye)))
2141 WriteLP(D_width - 1, oldbot);
2142 if (oldbot == D_bot) /* have scrolled */
2144 if (--n == 0)
2146 /* XXX
2147 ChangeScrollRegion(oldtop, oldbot);
2149 if (bce && !D_BE)
2150 ClearLine((struct mline *)0, ye, xs, xe, bce);
2151 return;
2156 if (D_UT)
2157 SetRendition(&mchar_null);
2158 #ifdef COLOR
2159 if (D_BE)
2160 SetBackColor(bce);
2161 #endif
2163 aldlfaster = (n > 1 && ys >= D_top && ye == D_bot && ((up && D_CDL) || (!up && D_CAL)));
2165 if ((up || D_SR) && D_top == ys && D_bot == ye && !aldlfaster)
2167 if (up)
2169 GotoPos(0, ye);
2170 for(i = n; i-- > 0; )
2171 AddCStr(D_NL); /* was SF, I think NL is faster */
2173 else
2175 GotoPos(0, ys);
2176 for(i = n; i-- > 0; )
2177 AddCStr(D_SR);
2180 else if (alok && dlok)
2182 if (up || ye != D_bot)
2184 GotoPos(0, up ? ys : ye+1-n);
2185 if (D_CDL && !(n == 1 && D_DL))
2186 AddCStr2(D_CDL, n);
2187 else
2188 for(i = n; i--; )
2189 AddCStr(D_DL);
2191 if (!up || ye != D_bot)
2193 GotoPos(0, up ? ye+1-n : ys);
2194 if (D_CAL && !(n == 1 && D_AL))
2195 AddCStr2(D_CAL, n);
2196 else
2197 for(i = n; i--; )
2198 AddCStr(D_AL);
2201 else
2203 RefreshArea(xs, ys, xe, ye, 0);
2204 return;
2206 if (bce && !D_BE)
2208 if (up)
2209 ClearArea(xs, ye - n + 1, xs, xe, xe, ye, bce, 0);
2210 else
2211 ClearArea(xs, ys, xs, xe, xe, ys + n - 1, bce, 0);
2213 if (D_lp_missing && missy != D_bot)
2214 WriteLP(D_width - 1, missy);
2215 /* XXX
2216 ChangeScrollRegion(oldtop, oldbot);
2217 if (D_lp_missing && missy != D_bot)
2218 WriteLP(D_width - 1, missy);
2222 void
2223 SetAttr(new)
2224 register int new;
2226 register int i, j, old, typ;
2228 if (!display || (old = D_rend.attr) == new)
2229 return;
2230 #ifdef COLORS16
2231 D_col16change = (old ^ new) & (A_BFG | A_BBG);
2232 new ^= D_col16change;
2233 if (old == new)
2234 return;
2235 #endif
2236 #if defined(TERMINFO) && defined(USE_SGR)
2237 if (D_SA)
2239 char *tparm();
2240 SetFont(ASCII);
2241 ospeed = D_dospeed;
2242 tputs(tparm(D_SA, new & A_SO, new & A_US, new & A_RV, new & A_BL,
2243 new & A_DI, new & A_BD, 0 , 0 ,
2244 0), 1, DoAddChar);
2245 D_rend.attr = new;
2246 D_atyp = 0;
2247 # ifdef COLOR
2248 if (D_hascolor)
2249 rend_setdefault(&D_rend);
2250 # endif
2251 return;
2253 #endif
2254 D_rend.attr = new;
2255 typ = D_atyp;
2256 if ((new & old) != old)
2258 if ((typ & ATYP_U))
2259 AddCStr(D_UE);
2260 if ((typ & ATYP_S))
2261 AddCStr(D_SE);
2262 if ((typ & ATYP_M))
2264 AddCStr(D_ME);
2265 #ifdef COLOR
2266 /* ansi attrib handling: \E[m resets color, too */
2267 if (D_hascolor)
2268 rend_setdefault(&D_rend);
2269 #endif
2270 #ifdef FONT
2271 if (!D_CG0)
2273 /* D_ME may also reset the alternate charset */
2274 D_rend.font = 0;
2275 # ifdef ENCODINGS
2276 D_realfont = 0;
2277 # endif
2279 #endif
2281 old = 0;
2282 typ = 0;
2284 old ^= new;
2285 for (i = 0, j = 1; old && i < NATTR; i++, j <<= 1)
2287 if ((old & j) == 0)
2288 continue;
2289 old ^= j;
2290 if (D_attrtab[i])
2292 AddCStr(D_attrtab[i]);
2293 typ |= D_attrtyp[i];
2296 D_atyp = typ;
2299 #ifdef FONT
2300 void
2301 SetFont(new)
2302 int new;
2304 int old = D_rend.font;
2305 if (!display || old == new)
2306 return;
2307 D_rend.font = new;
2308 #ifdef ENCODINGS
2309 if (D_encoding && CanEncodeFont(D_encoding, new))
2310 return;
2311 if (new == D_realfont)
2312 return;
2313 D_realfont = new;
2314 #endif
2315 if (D_xtable && D_xtable[(int)(unsigned char)new] &&
2316 D_xtable[(int)(unsigned char)new][256])
2318 AddCStr(D_xtable[(int)(unsigned char)new][256]);
2319 return;
2322 if (!D_CG0 && new != '0')
2324 new = ASCII;
2325 if (old == new)
2326 return;
2329 if (new == ASCII)
2330 AddCStr(D_CE0);
2331 #ifdef DW_CHARS
2332 else if (new < ' ')
2334 AddStr("\033$");
2335 if (new > 2)
2336 AddChar('(');
2337 AddChar(new + '@');
2339 #endif
2340 else
2341 AddCStr2(D_CS0, new);
2343 #endif
2345 #ifdef COLOR
2348 color256to16(jj)
2349 int jj;
2351 int min, max;
2352 int r, g, b;
2354 if (jj >= 232)
2356 jj = (jj - 232) / 6;
2357 jj = (jj & 1) << 3 | (jj & 2 ? 7 : 0);
2359 else if (jj >= 16)
2361 jj -= 16;
2362 r = jj / 36;
2363 g = (jj / 6) % 6;
2364 b = jj % 6;
2365 min = r < g ? (r < b ? r : b) : (g < b ? g : b);
2366 max = r > g ? (r > b ? r : b) : (g > b ? g : b);
2367 if (min == max)
2368 jj = ((max + 1) & 2) << 2 | ((max + 1) & 4 ? 7 : 0);
2369 else
2370 jj = (b - min) / (max - min) << 2 | (g - min) / (max - min) << 1 | (r -
2371 min) / (max - min) | (max > 3 ? 8 : 0);
2373 return jj;
2376 #ifdef COLORS256
2378 color256to88(jj)
2379 int jj;
2381 int r, g, b;
2383 if (jj >= 232)
2384 return (jj - 232) / 3 + 80;
2385 if (jj >= 16)
2387 jj -= 16;
2388 r = jj / 36;
2389 g = (jj / 6) % 6;
2390 b = jj % 6;
2391 return ((r + 1) / 2) * 16 + ((g + 1) / 2) * 4 + ((b + 1) / 2) + 16;
2393 return jj;
2395 #endif
2397 void
2398 SetColor(f, b)
2399 int f, b;
2401 int of, ob;
2402 static unsigned char sftrans[8] = {0,4,2,6,1,5,3,7};
2404 if (!display)
2405 return;
2407 of = rend_getfg(&D_rend);
2408 ob = rend_getbg(&D_rend);
2410 #ifdef COLORS16
2411 /* intense default not invented yet */
2412 if (f == 0x100)
2413 f = 0;
2414 if (b == 0x100)
2415 b = 0;
2416 #endif
2417 debug2("SetColor %d %d", coli2e(of), coli2e(ob));
2418 debug2(" -> %d %d\n", coli2e(f), coli2e(b));
2419 debug2("(%d %d", of, ob);
2420 debug2(" -> %d %d)\n", f, b);
2422 if (!D_CAX && D_hascolor && ((f == 0 && f != of) || (b == 0 && b != ob)))
2424 if (D_OP)
2425 AddCStr(D_OP);
2426 else
2428 int oattr;
2429 oattr = D_rend.attr;
2430 AddCStr(D_ME ? D_ME : "\033[m");
2431 #ifdef FONT
2432 if (D_ME && !D_CG0)
2434 /* D_ME may also reset the alternate charset */
2435 D_rend.font = 0;
2436 # ifdef ENCODINGS
2437 D_realfont = 0;
2438 # endif
2440 #endif
2441 D_atyp = 0;
2442 D_rend.attr = 0;
2443 SetAttr(oattr);
2445 of = ob = 0;
2447 rend_setfg(&D_rend, f);
2448 rend_setbg(&D_rend, b);
2449 #ifdef COLORS16
2450 D_col16change = 0;
2451 #endif
2452 if (!D_hascolor)
2453 return;
2454 f = f ? coli2e(f) : -1;
2455 b = b ? coli2e(b) : -1;
2456 of = of ? coli2e(of) : -1;
2457 ob = ob ? coli2e(ob) : -1;
2458 #ifdef COLORS256
2459 if (f != of && f > 15 && D_CCO != 256)
2460 f = D_CCO == 88 && D_CAF ? color256to88(f) : color256to16(f);
2461 if (f != of && f > 15 && D_CAF)
2463 AddCStr2(D_CAF, f);
2464 of = f;
2466 if (b != ob && b > 15 && D_CCO != 256)
2467 b = D_CCO == 88 && D_CAB ? color256to88(b) : color256to16(b);
2468 if (b != ob && b > 15 && D_CAB)
2470 AddCStr2(D_CAB, b);
2471 ob = b;
2473 #endif
2474 if (f != of && f != (of | 8))
2476 if (f == -1)
2477 AddCStr("\033[39m"); /* works because AX is set */
2478 else if (D_CAF)
2479 AddCStr2(D_CAF, f & 7);
2480 else if (D_CSF)
2481 AddCStr2(D_CSF, sftrans[f & 7]);
2483 if (b != ob && b != (ob | 8))
2485 if (b == -1)
2486 AddCStr("\033[49m"); /* works because AX is set */
2487 else if (D_CAB)
2488 AddCStr2(D_CAB, b & 7);
2489 else if (D_CSB)
2490 AddCStr2(D_CSB, sftrans[b & 7]);
2492 #ifdef COLORS16
2493 if (f != of && D_CXT && (f & 8) != 0 && f != -1)
2495 # ifdef TERMINFO
2496 AddCStr2("\033[9%p1%dm", f & 7);
2497 # else
2498 AddCStr2("\033[9%dm", f & 7);
2499 # endif
2501 if (b != ob && D_CXT && (b & 8) != 0 && b != -1)
2503 # ifdef TERMINFO
2504 AddCStr2("\033[10%p1%dm", b & 7);
2505 # else
2506 AddCStr2("\033[10%dm", b & 7);
2507 # endif
2509 #endif
2512 static void
2513 SetBackColor(new)
2514 int new;
2516 if (!display)
2517 return;
2518 SetColor(rend_getfg(&D_rend), new);
2520 #endif /* COLOR */
2522 void
2523 SetRendition(mc)
2524 struct mchar *mc;
2526 if (!display)
2527 return;
2528 if (nattr2color && D_hascolor && (mc->attr & nattr2color) != 0)
2530 static struct mchar mmc;
2531 int i;
2532 mmc = *mc;
2533 for (i = 0; i < 8; i++)
2534 if (attr2color[i] && (mc->attr & (1 << i)) != 0)
2536 if (mc->color == 0 && attr2color[i][3])
2537 ApplyAttrColor(attr2color[i][3], &mmc);
2538 else if ((mc->color & 0x0f) == 0 && attr2color[i][2])
2539 ApplyAttrColor(attr2color[i][2], &mmc);
2540 else if ((mc->color & 0xf0) == 0 && attr2color[i][1])
2541 ApplyAttrColor(attr2color[i][1], &mmc);
2542 else
2543 ApplyAttrColor(attr2color[i][0], &mmc);
2545 mc = &mmc;
2546 debug2("SetRendition: mapped to %02x %02x\n", (unsigned char)mc->attr, 0x99 - (unsigned char)mc->color);
2548 if (D_hascolor && D_CC8 && (mc->attr & (A_BFG|A_BBG)))
2550 int a = mc->attr;
2551 if ((mc->attr & A_BFG) && D_MD)
2552 a |= A_BD;
2553 if ((mc->attr & A_BBG) && D_MB)
2554 a |= A_BL;
2555 if (D_rend.attr != a)
2556 SetAttr(a);
2558 else if (D_rend.attr != mc->attr)
2559 SetAttr(mc->attr);
2560 #ifdef COLOR
2561 if (D_rend.color != mc->color
2562 # ifdef COLORS256
2563 || D_rend.colorx != mc->colorx
2564 # endif
2565 # ifdef COLORS16
2566 || D_col16change
2567 # endif
2569 SetColor(rend_getfg(mc), rend_getbg(mc));
2570 #endif
2571 #ifdef FONT
2572 if (D_rend.font != mc->font)
2573 SetFont(mc->font);
2574 #endif
2577 void
2578 SetRenditionMline(ml, x)
2579 struct mline *ml;
2580 int x;
2582 if (!display)
2583 return;
2584 if (nattr2color && D_hascolor && (ml->attr[x] & nattr2color) != 0)
2586 struct mchar mc;
2587 copy_mline2mchar(&mc, ml, x);
2588 SetRendition(&mc);
2589 return;
2591 if (D_hascolor && D_CC8 && (ml->attr[x] & (A_BFG|A_BBG)))
2593 int a = ml->attr[x];
2594 if ((ml->attr[x] & A_BFG) && D_MD)
2595 a |= A_BD;
2596 if ((ml->attr[x] & A_BBG) && D_MB)
2597 a |= A_BL;
2598 if (D_rend.attr != a)
2599 SetAttr(a);
2601 else if (D_rend.attr != ml->attr[x])
2602 SetAttr(ml->attr[x]);
2603 #ifdef COLOR
2604 if (D_rend.color != ml->color[x]
2605 # ifdef COLORS256
2606 || D_rend.colorx != ml->colorx[x]
2607 # endif
2608 # ifdef COLORS16
2609 || D_col16change
2610 # endif
2613 struct mchar mc;
2614 copy_mline2mchar(&mc, ml, x);
2615 SetColor(rend_getfg(&mc), rend_getbg(&mc));
2617 #endif
2618 #ifdef FONT
2619 if (D_rend.font != ml->font[x])
2620 SetFont(ml->font[x]);
2621 #endif
2624 void
2625 MakeStatus(msg)
2626 char *msg;
2628 register char *s, *t;
2629 register int max;
2631 if (!display)
2632 return;
2634 if (D_blocked)
2635 return;
2636 if (!D_tcinited)
2638 debug("tc not inited, just writing msg\n");
2639 if (D_processinputdata)
2640 return; /* XXX: better */
2641 AddStr(msg);
2642 AddStr("\r\n");
2643 Flush();
2644 return;
2646 if (!use_hardstatus || !D_HS)
2648 max = D_width;
2649 if (D_CLP == 0)
2650 max--;
2652 else
2653 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2654 if (D_status)
2656 /* same message? */
2657 if (strcmp(msg, D_status_lastmsg) == 0)
2659 debug("same message - increase timeout");
2660 SetTimeout(&D_statusev, MsgWait);
2661 return;
2663 if (!D_status_bell)
2665 struct timeval now;
2666 int ti;
2667 gettimeofday(&now, NULL);
2668 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
2669 if (ti < MsgMinWait)
2670 DisplaySleep1000(MsgMinWait - ti, 0);
2672 RemoveStatus();
2674 for (s = t = msg; *s && t - msg < max; ++s)
2675 if (*s == BELL)
2676 AddCStr(D_BL);
2677 else if ((unsigned char)*s >= ' ' && *s != 0177)
2678 *t++ = *s;
2679 *t = '\0';
2680 if (t == msg)
2681 return;
2682 if (t - msg >= D_status_buflen)
2684 char *buf;
2685 if (D_status_lastmsg)
2686 buf = realloc(D_status_lastmsg, t - msg + 1);
2687 else
2688 buf = malloc(t - msg + 1);
2689 if (buf)
2691 D_status_lastmsg = buf;
2692 D_status_buflen = t - msg + 1;
2695 if (t - msg < D_status_buflen)
2696 strcpy(D_status_lastmsg, msg);
2697 D_status_len = t - msg;
2698 D_status_lastx = D_x;
2699 D_status_lasty = D_y;
2700 if (!use_hardstatus || D_has_hstatus == HSTATUS_IGNORE || D_has_hstatus == HSTATUS_MESSAGE)
2702 D_status = STATUS_ON_WIN;
2703 debug1("using STATLINE %d\n", STATLINE);
2704 GotoPos(0, STATLINE);
2705 SetRendition(&mchar_so);
2706 InsertMode(0);
2707 AddStr(msg);
2708 if (D_status_len < max)
2710 /* Wayne Davison: add extra space for readability */
2711 D_status_len++;
2712 SetRendition(&mchar_null);
2713 AddChar(' ');
2714 if (D_status_len < max)
2716 D_status_len++;
2717 AddChar(' ');
2718 AddChar('\b');
2720 AddChar('\b');
2722 D_x = -1;
2724 else
2726 D_status = STATUS_ON_HS;
2727 ShowHStatus(msg);
2729 Flush();
2730 if (!display)
2731 return;
2732 if (D_status == STATUS_ON_WIN)
2734 struct display *olddisplay = display;
2735 struct layer *oldflayer = flayer;
2737 ASSERT(D_obuffree == D_obuflen);
2738 /* this is copied over from RemoveStatus() */
2739 D_status = 0;
2740 GotoPos(0, STATLINE);
2741 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2742 GotoPos(D_status_lastx, D_status_lasty);
2743 flayer = D_forecv ? D_forecv->c_layer : 0;
2744 if (flayer)
2745 LaySetCursor();
2746 display = olddisplay;
2747 flayer = oldflayer;
2748 D_status_obuflen = D_obuflen;
2749 D_status_obuffree = D_obuffree;
2750 D_obuffree = D_obuflen = 0;
2751 D_status = STATUS_ON_WIN;
2753 gettimeofday(&D_status_time, NULL);
2754 SetTimeout(&D_statusev, MsgWait);
2755 evenq(&D_statusev);
2756 #ifdef HAVE_BRAILLE
2757 RefreshBraille(); /* let user see multiple Msg()s */
2758 #endif
2761 void
2762 RemoveStatus()
2764 struct display *olddisplay;
2765 struct layer *oldflayer;
2766 int where;
2768 if (!display)
2769 return;
2770 if (!(where = D_status))
2771 return;
2773 debug("RemoveStatus\n");
2774 if (D_status_obuffree >= 0)
2776 D_obuflen = D_status_obuflen;
2777 D_obuffree = D_status_obuffree;
2778 D_status_obuffree = -1;
2779 D_status = 0;
2780 D_status_bell = 0;
2781 evdeq(&D_statusev);
2782 return;
2784 D_status = 0;
2785 D_status_bell = 0;
2786 evdeq(&D_statusev);
2787 olddisplay = display;
2788 oldflayer = flayer;
2789 if (where == STATUS_ON_WIN)
2791 GotoPos(0, STATLINE);
2792 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2793 GotoPos(D_status_lastx, D_status_lasty);
2795 else
2796 RefreshHStatus();
2797 flayer = D_forecv ? D_forecv->c_layer : 0;
2798 if (flayer)
2799 LaySetCursor();
2800 display = olddisplay;
2801 flayer = oldflayer;
2804 /* refresh the display's hstatus line */
2805 void
2806 ShowHStatus(str)
2807 char *str;
2809 int l, ox, oy, max;
2811 if (D_status == STATUS_ON_WIN && D_has_hstatus == HSTATUS_LASTLINE && STATLINE == D_height-1)
2812 return; /* sorry, in use */
2813 if (D_blocked)
2814 return;
2816 if (D_HS && D_has_hstatus == HSTATUS_HS)
2818 if (!D_hstatus && (str == 0 || *str == 0))
2819 return;
2820 debug("ShowHStatus: using HS\n");
2821 SetRendition(&mchar_null);
2822 InsertMode(0);
2823 if (D_hstatus)
2824 AddCStr(D_DS);
2825 D_hstatus = 0;
2826 if (str == 0 || *str == 0)
2827 return;
2828 AddCStr2(D_TS, 0);
2829 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2830 if ((int)strlen(str) > max)
2831 AddStrn(str, max);
2832 else
2833 AddStr(str);
2834 AddCStr(D_FS);
2835 D_hstatus = 1;
2837 else if (D_has_hstatus == HSTATUS_LASTLINE)
2839 debug("ShowHStatus: using last line\n");
2840 ox = D_x;
2841 oy = D_y;
2842 str = str ? str : "";
2843 l = strlen(str);
2844 if (l > D_width)
2845 l = D_width;
2846 GotoPos(0, D_height - 1);
2847 SetRendition(captionalways || D_cvlist == 0 || D_cvlist->c_next ? &mchar_null: &mchar_so);
2848 PutWinMsg(str, 0, l);
2849 if (!captionalways && D_cvlist && !D_cvlist->c_next)
2850 while (l++ < D_width)
2851 PUTCHARLP(' ');
2852 if (l < D_width)
2853 ClearArea(l, D_height - 1, l, D_width - 1, D_width - 1, D_height - 1, 0, 0);
2854 if (ox != -1 && oy != -1)
2855 GotoPos(ox, oy);
2856 D_hstatus = *str ? 1 : 0;
2857 SetRendition(&mchar_null);
2859 else if (str && *str && D_has_hstatus == HSTATUS_MESSAGE)
2861 debug("ShowHStatus: using message\n");
2862 Msg(0, "%s", str);
2868 * Refreshes the harstatus of the fore window. Shouldn't be here...
2870 void
2871 RefreshHStatus()
2873 char *buf;
2875 evdeq(&D_hstatusev);
2876 if (D_status == STATUS_ON_HS)
2877 return;
2878 buf = MakeWinMsgEv(hstatusstring, D_fore, '%', (D_HS && D_has_hstatus == HSTATUS_HS && D_WS > 0) ? D_WS : D_width - !D_CLP, &D_hstatusev, 0);
2879 if (buf && *buf)
2881 ShowHStatus(buf);
2882 if (D_has_hstatus != HSTATUS_IGNORE && D_hstatusev.timeout.tv_sec)
2883 evenq(&D_hstatusev);
2885 else
2886 ShowHStatus((char *)0);
2889 /*********************************************************************/
2891 * Here come the routines that refresh an arbitrary part of the screen.
2894 void
2895 RefreshAll(isblank)
2896 int isblank;
2898 struct canvas *cv;
2900 ASSERT(display);
2901 debug("Signalling full refresh!\n");
2902 for (cv = D_cvlist; cv; cv = cv->c_next)
2904 CV_CALL(cv, LayRedisplayLine(-1, -1, -1, isblank));
2905 display = cv->c_display; /* just in case! */
2907 RefreshArea(0, 0, D_width - 1, D_height - 1, isblank);
2910 void
2911 RefreshArea(xs, ys, xe, ye, isblank)
2912 int xs, ys, xe, ye, isblank;
2914 int y;
2915 ASSERT(display);
2916 debug2("Refresh Area: %d,%d", xs, ys);
2917 debug3(" - %d,%d (isblank=%d)\n", xe, ye, isblank);
2918 if (!isblank && xs == 0 && xe == D_width - 1 && ye == D_height - 1 && (ys == 0 || D_CD))
2920 ClearArea(xs, ys, xs, xe, xe, ye, 0, 0);
2921 isblank = 1;
2923 for (y = ys; y <= ye; y++)
2924 RefreshLine(y, xs, xe, isblank);
2927 void
2928 RefreshLine(y, from, to, isblank)
2929 int y, from, to, isblank;
2931 struct viewport *vp, *lvp;
2932 struct canvas *cv, *lcv, *cvlist, *cvlnext;
2933 struct layer *oldflayer;
2934 int xx, yy, l;
2935 char *buf;
2936 struct win *p;
2938 ASSERT(display);
2940 debug2("RefreshLine %d %d", y, from);
2941 debug2(" %d %d\n", to, isblank);
2943 if (D_status == STATUS_ON_WIN && y == STATLINE)
2944 return; /* can't refresh status */
2946 if (y == D_height - 1 && D_has_hstatus == HSTATUS_LASTLINE)
2948 RefreshHStatus();
2949 return;
2952 if (isblank == 0 && D_CE && to == D_width - 1 && from < to)
2954 GotoPos(from, y);
2955 if (D_UT || D_BE)
2956 SetRendition(&mchar_null);
2957 AddCStr(D_CE);
2958 isblank = 1;
2960 while (from <= to)
2962 lcv = 0;
2963 lvp = 0;
2964 for (cv = display->d_cvlist; cv; cv = cv->c_next)
2966 if (y == cv->c_ye + 1 && from >= cv->c_xs && from <= cv->c_xe)
2968 p = Layer2Window(cv->c_layer);
2969 buf = MakeWinMsgEv(captionstring, p, '%', cv->c_xe - cv->c_xs + (cv->c_xe + 1 < D_width || D_CLP), &cv->c_captev, 0);
2970 if (cv->c_captev.timeout.tv_sec)
2971 evenq(&cv->c_captev);
2972 xx = to > cv->c_xe ? cv->c_xe : to;
2973 l = strlen(buf);
2974 GotoPos(from, y);
2975 SetRendition(&mchar_so);
2976 if (l > xx - cv->c_xs + 1)
2977 l = xx - cv->c_xs + 1;
2978 PutWinMsg(buf, from - cv->c_xs, l);
2979 from = cv->c_xs + l;
2980 for (; from <= xx; from++)
2981 PUTCHARLP(' ');
2982 break;
2984 if (from == cv->c_xe + 1 && y >= cv->c_ys && y <= cv->c_ye + 1)
2986 GotoPos(from, y);
2987 SetRendition(&mchar_so);
2988 PUTCHARLP(' ');
2989 from++;
2990 break;
2992 if (y < cv->c_ys || y > cv->c_ye || to < cv->c_xs || from > cv->c_xe)
2993 continue;
2994 debug2("- canvas hit: %d %d", cv->c_xs, cv->c_ys);
2995 debug2(" %d %d\n", cv->c_xe, cv->c_ye);
2996 for (vp = cv->c_vplist; vp; vp = vp->v_next)
2998 debug2(" - vp: %d %d", vp->v_xs, vp->v_ys);
2999 debug2(" %d %d\n", vp->v_xe, vp->v_ye);
3000 /* find leftmost overlapping vp */
3001 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))
3003 lcv = cv;
3004 lvp = vp;
3008 if (cv)
3009 continue; /* we advanced from */
3010 if (lvp == 0)
3011 break;
3012 if (from < lvp->v_xs)
3014 if (!isblank)
3015 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xs - 1);
3016 from = lvp->v_xs;
3019 /* call LayRedisplayLine on canvas lcv viewport lvp */
3020 yy = y - lvp->v_yoff;
3021 xx = to < lvp->v_xe ? to : lvp->v_xe;
3023 if (lcv->c_layer && yy == lcv->c_layer->l_height)
3025 GotoPos(from, y);
3026 SetRendition(&mchar_blank);
3027 while (from <= lvp->v_xe && from - lvp->v_xoff < lcv->c_layer->l_width)
3029 PUTCHARLP('-');
3030 from++;
3032 if (from >= lvp->v_xe + 1)
3033 continue;
3035 if (lcv->c_layer == 0 || yy >= lcv->c_layer->l_height || from - lvp->v_xoff >= lcv->c_layer->l_width)
3037 if (!isblank)
3038 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xe);
3039 from = lvp->v_xe + 1;
3040 continue;
3043 if (xx - lvp->v_xoff >= lcv->c_layer->l_width)
3044 xx = lcv->c_layer->l_width + lvp->v_xoff - 1;
3045 oldflayer = flayer;
3046 flayer = lcv->c_layer;
3047 cvlist = flayer->l_cvlist;
3048 cvlnext = lcv->c_lnext;
3049 flayer->l_cvlist = lcv;
3050 lcv->c_lnext = 0;
3051 LayRedisplayLine(yy, from - lvp->v_xoff, xx - lvp->v_xoff, isblank);
3052 flayer->l_cvlist = cvlist;
3053 lcv->c_lnext = cvlnext;
3054 flayer = oldflayer;
3056 from = xx + 1;
3058 if (!isblank && from <= to)
3059 DisplayLine(&mline_null, &mline_blank, y, from, to);
3062 /*********************************************************************/
3064 /* clear lp_missing by writing the char on the screen. The
3065 * position must be safe.
3067 static void
3068 WriteLP(x2, y2)
3069 int x2, y2;
3071 struct mchar oldrend;
3073 ASSERT(display);
3074 ASSERT(D_lp_missing);
3075 oldrend = D_rend;
3076 debug2("WriteLP(%d,%d)\n", x2, y2);
3077 #ifdef DW_CHARS
3078 if (D_lpchar.mbcs)
3080 if (x2 > 0)
3081 x2--;
3082 else
3083 D_lpchar = mchar_blank;
3085 #endif
3086 /* Can't use PutChar */
3087 GotoPos(x2, y2);
3088 SetRendition(&D_lpchar);
3089 PUTCHAR(D_lpchar.image);
3090 #ifdef DW_CHARS
3091 if (D_lpchar.mbcs)
3092 PUTCHAR(D_lpchar.mbcs);
3093 #endif
3094 D_lp_missing = 0;
3095 SetRendition(&oldrend);
3098 void
3099 ClearLine(oml, y, from, to, bce)
3100 struct mline *oml;
3101 int from, to, y, bce;
3103 int x;
3104 #ifdef COLOR
3105 struct mchar bcechar;
3106 #endif
3108 debug3("ClearLine %d,%d-%d\n", y, from, to);
3109 if (D_UT) /* Safe to erase ? */
3110 SetRendition(&mchar_null);
3111 #ifdef COLOR
3112 if (D_BE)
3113 SetBackColor(bce);
3114 #endif
3115 if (from == 0 && D_CB && (to != D_width - 1 || (D_x == to && D_y == y)) && (!bce || D_BE))
3117 GotoPos(to, y);
3118 AddCStr(D_CB);
3119 return;
3121 if (to == D_width - 1 && D_CE && (!bce || D_BE))
3123 GotoPos(from, y);
3124 AddCStr(D_CE);
3125 return;
3127 if (oml == 0)
3128 oml = &mline_null;
3129 #ifdef COLOR
3130 if (!bce)
3132 DisplayLine(oml, &mline_blank, y, from, to);
3133 return;
3135 bcechar = mchar_blank;
3136 rend_setbg(&bcechar, bce);
3137 for (x = from; x <= to; x++)
3138 copy_mchar2mline(&bcechar, &mline_old, x);
3139 DisplayLine(oml, &mline_old, y, from, to);
3140 #else
3141 DisplayLine(oml, &mline_blank, y, from, to);
3142 #endif
3145 void
3146 DisplayLine(oml, ml, y, from, to)
3147 struct mline *oml, *ml;
3148 int from, to, y;
3150 register int x;
3151 int last2flag = 0, delete_lp = 0;
3153 ASSERT(display);
3154 ASSERT(y >= 0 && y < D_height);
3155 ASSERT(from >= 0 && from < D_width);
3156 ASSERT(to >= 0 && to < D_width);
3157 if (!D_CLP && y == D_bot && to == D_width - 1)
3159 if (D_lp_missing || !cmp_mline(oml, ml, to))
3161 #ifdef DW_CHARS
3162 if ((D_IC || D_IM) && from < to && !dw_left(ml, to, D_encoding))
3163 #else
3164 if ((D_IC || D_IM) && from < to)
3165 #endif
3167 last2flag = 1;
3168 D_lp_missing = 0;
3169 to--;
3171 else
3173 delete_lp = !cmp_mchar_mline(&mchar_blank, oml, to) && (D_CE || D_DC || D_CDC);
3174 D_lp_missing = !cmp_mchar_mline(&mchar_blank, ml, to);
3175 copy_mline2mchar(&D_lpchar, ml, to);
3178 to--;
3180 #ifdef DW_CHARS
3181 if (D_mbcs)
3183 /* finish dw-char (can happen after a wrap) */
3184 debug("DisplayLine finishing kanji\n");
3185 SetRenditionMline(ml, from);
3186 PUTCHAR(ml->image[from]);
3187 from++;
3189 #endif
3190 for (x = from; x <= to; x++)
3192 #if 0 /* no longer needed */
3193 if (x || D_x != D_width || D_y != y - 1)
3194 #endif
3196 if (x < to || x != D_width - 1 || ml->image[x + 1])
3197 if (cmp_mline(oml, ml, x))
3198 continue;
3199 GotoPos(x, y);
3201 #ifdef DW_CHARS
3202 if (dw_right(ml, x, D_encoding))
3204 x--;
3205 debug1("DisplayLine on right side of dw char- x now %d\n", x);
3206 GotoPos(x, y);
3208 if (x == to && dw_left(ml, x, D_encoding))
3209 break; /* don't start new kanji */
3210 #endif
3211 SetRenditionMline(ml, x);
3212 PUTCHAR(ml->image[x]);
3213 #ifdef DW_CHARS
3214 if (dw_left(ml, x, D_encoding))
3215 PUTCHAR(ml->image[++x]);
3216 #endif
3218 #if 0 /* not needed any longer */
3219 /* compare != 0 because ' ' can happen when clipping occures */
3220 if (to == D_width - 1 && y < D_height - 1 && D_x == D_width && ml->image[to + 1])
3221 GotoPos(0, y + 1);
3222 #endif
3223 if (last2flag)
3225 GotoPos(x, y);
3226 SetRenditionMline(ml, x + 1);
3227 PUTCHAR(ml->image[x + 1]);
3228 GotoPos(x, y);
3229 SetRenditionMline(ml, x);
3230 INSERTCHAR(ml->image[x]);
3232 else if (delete_lp)
3234 if (D_UT)
3235 SetRendition(&mchar_null);
3236 if (D_DC)
3237 AddCStr(D_DC);
3238 else if (D_CDC)
3239 AddCStr2(D_CDC, 1);
3240 else if (D_CE)
3241 AddCStr(D_CE);
3245 void
3246 PutChar(c, x, y)
3247 struct mchar *c;
3248 int x, y;
3250 GotoPos(x, y);
3251 SetRendition(c);
3252 PUTCHARLP(c->image);
3253 #ifdef DW_CHARS
3254 if (c->mbcs)
3256 # ifdef UTF8
3257 if (D_encoding == UTF8)
3258 D_rend.font = 0;
3259 # endif
3260 PUTCHARLP(c->mbcs);
3262 #endif
3265 void
3266 InsChar(c, x, xe, y, oml)
3267 struct mchar *c;
3268 int x, xe, y;
3269 struct mline *oml;
3271 GotoPos(x, y);
3272 if (y == D_bot && !D_CLP)
3274 if (x == D_width - 1)
3276 D_lp_missing = 1;
3277 D_lpchar = *c;
3278 return;
3280 if (xe == D_width - 1)
3281 D_lp_missing = 0;
3283 if (x == xe)
3285 SetRendition(c);
3286 PUTCHARLP(c->image);
3287 return;
3289 if (!(D_IC || D_CIC || D_IM) || xe != D_width - 1)
3291 RefreshLine(y, x, xe, 0);
3292 GotoPos(x + 1, y);
3293 /* UpdateLine(oml, y, x, xe); */
3294 return;
3296 InsertMode(1);
3297 if (!D_insert)
3299 #ifdef DW_CHARS
3300 if (c->mbcs && D_IC)
3301 AddCStr(D_IC);
3302 if (D_IC)
3303 AddCStr(D_IC);
3304 else
3305 AddCStr2(D_CIC, c->mbcs ? 2 : 1);
3306 #else
3307 if (D_IC)
3308 AddCStr(D_IC);
3309 else
3310 AddCStr2(D_CIC, 1);
3311 #endif
3313 SetRendition(c);
3314 RAW_PUTCHAR(c->image);
3315 #ifdef DW_CHARS
3316 if (c->mbcs)
3318 # ifdef UTF8
3319 if (D_encoding == UTF8)
3320 D_rend.font = 0;
3321 # endif
3322 if (D_x == D_width - 1)
3323 PUTCHARLP(c->mbcs);
3324 else
3325 RAW_PUTCHAR(c->mbcs);
3327 #endif
3330 void
3331 WrapChar(c, x, y, xs, ys, xe, ye, ins)
3332 struct mchar *c;
3333 int x, y;
3334 int xs, ys, xe, ye;
3335 int ins;
3337 int bce;
3339 #ifdef COLOR
3340 bce = rend_getbg(c);
3341 #else
3342 bce = 0;
3343 #endif
3344 debug("WrapChar:");
3345 debug2(" x %d y %d", x, y);
3346 debug2(" Dx %d Dy %d", D_x, D_y);
3347 debug2(" xs %d ys %d", xs, ys);
3348 debug3(" xe %d ye %d ins %d\n", xe, ye, ins);
3349 if (xs != 0 || x != D_width || !D_AM)
3351 if (y == ye)
3352 ScrollV(xs, ys, xe, ye, 1, bce);
3353 else if (y < D_height - 1)
3354 y++;
3355 if (ins)
3356 InsChar(c, xs, xe, y, 0);
3357 else
3358 PutChar(c, xs, y);
3359 return;
3361 if (y == ye) /* we have to scroll */
3363 debug("- scrolling\n");
3364 ChangeScrollRegion(ys, ye);
3365 if (D_bot != y || D_x != D_width || (!bce && !D_BE))
3367 debug("- have to call ScrollV\n");
3368 ScrollV(xs, ys, xe, ye, 1, bce);
3369 y--;
3372 else if (y == D_bot) /* remove unusable region? */
3373 ChangeScrollRegion(0, D_height - 1);
3374 if (D_x != D_width || D_y != y)
3376 if (D_CLP && y >= 0) /* don't even try if !LP */
3377 RefreshLine(y, D_width - 1, D_width - 1, 0);
3378 debug2("- refresh last char -> x,y now %d,%d\n", D_x, D_y);
3379 if (D_x != D_width || D_y != y) /* sorry, no bonus */
3381 if (y == ye)
3382 ScrollV(xs, ys, xe, ye, 1, bce);
3383 GotoPos(xs, y == ye || y == D_height - 1 ? y : y + 1);
3386 debug("- writeing new char");
3387 if (y != ye && y < D_height - 1)
3388 y++;
3389 if (ins != D_insert)
3390 InsertMode(ins);
3391 if (ins && !D_insert)
3393 InsChar(c, 0, xe, y, 0);
3394 debug2(" -> done with insert (%d,%d)\n", D_x, D_y);
3395 return;
3397 D_y = y;
3398 D_x = 0;
3399 SetRendition(c);
3400 RAW_PUTCHAR(c->image);
3401 #ifdef DW_CHARS
3402 if (c->mbcs)
3404 # ifdef UTF8
3405 if (D_encoding == UTF8)
3406 D_rend.font = 0;
3407 # endif
3408 RAW_PUTCHAR(c->mbcs);
3410 #endif
3411 debug2(" -> done (%d,%d)\n", D_x, D_y);
3415 ResizeDisplay(wi, he)
3416 int wi, he;
3418 ASSERT(display);
3419 debug2("ResizeDisplay: to (%d,%d).\n", wi, he);
3420 if (D_width == wi && D_height == he)
3422 debug("ResizeDisplay: No change\n");
3423 return 0;
3425 if (D_width != wi && (D_height == he || !D_CWS) && D_CZ0 && (wi == Z0width || wi == Z1width))
3427 debug("ResizeDisplay: using Z0/Z1\n");
3428 AddCStr(wi == Z0width ? D_CZ0 : D_CZ1);
3429 ChangeScreenSize(wi, D_height, 0);
3430 return (he == D_height) ? 0 : -1;
3432 if (D_CWS)
3434 debug("ResizeDisplay: using WS\n");
3435 AddCStr(tgoto(D_CWS, wi, he));
3436 ChangeScreenSize(wi, he, 0);
3437 return 0;
3439 return -1;
3442 void
3443 ChangeScrollRegion(newtop, newbot)
3444 int newtop, newbot;
3446 if (display == 0)
3447 return;
3448 if (newtop == newbot)
3449 return; /* xterm etc can't do it */
3450 if (newtop == -1)
3451 newtop = 0;
3452 if (newbot == -1)
3453 newbot = D_height - 1;
3454 if (D_CS == 0)
3456 D_top = 0;
3457 D_bot = D_height - 1;
3458 return;
3460 if (D_top == newtop && D_bot == newbot)
3461 return;
3462 debug2("ChangeScrollRegion: (%d - %d)\n", newtop, newbot);
3463 AddCStr(tgoto(D_CS, newbot, newtop));
3464 D_top = newtop;
3465 D_bot = newbot;
3466 D_y = D_x = -1; /* Just in case... */
3469 #ifdef RXVT_OSC
3470 void
3471 SetXtermOSC(i, s)
3472 int i;
3473 char *s;
3475 static char oscs[] = "1;\000\00020;\00039;\00049;\000";
3477 ASSERT(display);
3478 if (!D_CXT)
3479 return;
3480 if (!s)
3481 s = "";
3482 if (!D_xtermosc[i] && !*s)
3483 return;
3484 if (i == 0 && !*s)
3485 s = "screen"; /* always set icon name */
3486 if (i == 1 && !*s)
3487 s = ""; /* no background */
3488 if (i == 2 && !*s)
3489 s = "black"; /* black text */
3490 if (i == 3 && !*s)
3491 s = "white"; /* on white background */
3492 D_xtermosc[i] = 1;
3493 AddStr("\033]");
3494 AddStr(oscs + i * 4);
3495 AddStr(s);
3496 AddChar(7);
3499 void
3500 ClearAllXtermOSC()
3502 int i;
3503 for (i = 3; i >= 0; i--)
3504 SetXtermOSC(i, 0);
3506 #endif
3509 * Output buffering routines
3512 void
3513 AddStr(str)
3514 char *str;
3516 register char c;
3518 ASSERT(display);
3520 #ifdef UTF8
3521 if (D_encoding == UTF8)
3523 while ((c = *str++))
3524 AddUtf8((unsigned char)c);
3525 return;
3527 #endif
3528 while ((c = *str++))
3529 AddChar(c);
3532 void
3533 AddStrn(str, n)
3534 char *str;
3535 int n;
3537 register char c;
3539 ASSERT(display);
3540 #ifdef UTF8
3541 if (D_encoding == UTF8)
3543 while ((c = *str++) && n-- > 0)
3544 AddUtf8((unsigned char)c);
3546 else
3547 #endif
3548 while ((c = *str++) && n-- > 0)
3549 AddChar(c);
3550 while (n-- > 0)
3551 AddChar(' ');
3554 void
3555 Flush()
3557 register int l;
3558 register char *p;
3560 ASSERT(display);
3561 l = D_obufp - D_obuf;
3562 debug1("Flush(): %d\n", l);
3563 if (l == 0)
3564 return;
3565 ASSERT(l + D_obuffree == D_obuflen);
3566 if (D_userfd < 0)
3568 D_obuffree += l;
3569 D_obufp = D_obuf;
3570 return;
3572 p = D_obuf;
3573 if (fcntl(D_userfd, F_SETFL, 0))
3574 debug1("Warning: BLOCK fcntl failed: %d\n", errno);
3575 while (l)
3577 register int wr;
3578 wr = write(D_userfd, p, l);
3579 if (wr <= 0)
3581 if (errno == EINTR)
3582 continue;
3583 debug1("Writing to display: %d\n", errno);
3584 wr = l;
3586 if (!display)
3587 return;
3588 D_obuffree += wr;
3589 p += wr;
3590 l -= wr;
3592 D_obuffree += l;
3593 D_obufp = D_obuf;
3594 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
3595 debug1("Warning: NBLOCK fcntl failed: %d\n", errno);
3596 if (D_blocked == 1)
3597 D_blocked = 0;
3598 D_blocked_fuzz = 0;
3601 void
3602 freetty()
3604 if (D_userfd >= 0)
3605 close(D_userfd);
3606 debug1("did freetty %d\n", D_userfd);
3607 D_userfd = -1;
3608 D_obufp = 0;
3609 D_obuffree = 0;
3610 if (D_obuf)
3611 free(D_obuf);
3612 D_obuf = 0;
3613 D_obuflen = 0;
3614 D_obuflenmax = -D_obufmax;
3615 D_blocked = 0;
3616 D_blocked_fuzz = 0;
3620 * Asynchronous output routines by
3621 * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
3624 void
3625 Resize_obuf()
3627 register int ind;
3629 ASSERT(display);
3630 if (D_status_obuffree >= 0)
3632 ASSERT(D_obuffree == -1);
3633 if (!D_status_bell)
3635 struct timeval now;
3636 int ti;
3637 gettimeofday(&now, NULL);
3638 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
3639 if (ti < MsgMinWait)
3640 DisplaySleep1000(MsgMinWait - ti, 0);
3642 RemoveStatus();
3643 if (--D_obuffree > 0) /* redo AddChar decrement */
3644 return;
3646 if (D_obuflen && D_obuf)
3648 ind = D_obufp - D_obuf;
3649 D_obuflen += GRAIN;
3650 D_obuffree += GRAIN;
3651 D_obuf = realloc(D_obuf, D_obuflen);
3653 else
3655 ind = 0;
3656 D_obuflen = GRAIN;
3657 D_obuffree = GRAIN;
3658 D_obuf = malloc(D_obuflen);
3660 if (!D_obuf)
3661 Panic(0, "Out of memory");
3662 D_obufp = D_obuf + ind;
3663 D_obuflenmax = D_obuflen - D_obufmax;
3664 debug1("ResizeObuf: resized to %d\n", D_obuflen);
3667 void
3668 DisplaySleep1000(n, eat)
3669 int n;
3670 int eat;
3672 char buf;
3673 fd_set r;
3674 struct timeval t;
3676 if (n <= 0)
3677 return;
3678 if (!display)
3680 debug("DisplaySleep has no display sigh\n");
3681 sleep1000(n);
3682 return;
3684 t.tv_usec = (n % 1000) * 1000;
3685 t.tv_sec = n / 1000;
3686 FD_ZERO(&r);
3687 FD_SET(D_userfd, &r);
3688 if (select(FD_SETSIZE, &r, (fd_set *)0, (fd_set *)0, &t) > 0)
3690 debug("display activity stopped sleep\n");
3691 if (eat)
3692 read(D_userfd, &buf, 1);
3694 debug2("DisplaySleep(%d) ending, eat was %d\n", n, eat);
3697 #ifdef AUTO_NUKE
3698 void
3699 NukePending()
3700 {/* Nuke pending output in current display, clear screen */
3701 register int len;
3702 int oldtop = D_top, oldbot = D_bot;
3703 struct mchar oldrend;
3704 int oldkeypad = D_keypad, oldcursorkeys = D_cursorkeys;
3705 int oldcurvis = D_curvis;
3706 int oldmouse = D_mouse;
3708 oldrend = D_rend;
3709 len = D_obufp - D_obuf;
3710 debug1("NukePending: nuking %d chars\n", len);
3712 /* Throw away any output that we can... */
3713 # ifdef POSIX
3714 tcflush(D_userfd, TCOFLUSH);
3715 # else
3716 # ifdef TCFLSH
3717 (void) ioctl(D_userfd, TCFLSH, (char *) 1);
3718 # endif
3719 # endif
3721 D_obufp = D_obuf;
3722 D_obuffree += len;
3723 D_top = D_bot = -1;
3724 AddCStr(D_TI);
3725 AddCStr(D_IS);
3726 /* Turn off all attributes. (Tim MacKenzie) */
3727 if (D_ME)
3728 AddCStr(D_ME);
3729 else
3731 #ifdef COLOR
3732 if (D_hascolor)
3733 AddStr("\033[m"); /* why is D_ME not set? */
3734 #endif
3735 AddCStr(D_SE);
3736 AddCStr(D_UE);
3738 /* Check for toggle */
3739 if (D_IM && strcmp(D_IM, D_EI))
3740 AddCStr(D_EI);
3741 D_insert = 0;
3742 /* Check for toggle */
3743 #ifdef MAPKEYS
3744 if (D_KS && strcmp(D_KS, D_KE))
3745 AddCStr(D_KS);
3746 if (D_CCS && strcmp(D_CCS, D_CCE))
3747 AddCStr(D_CCS);
3748 #else
3749 if (D_KS && strcmp(D_KS, D_KE))
3750 AddCStr(D_KE);
3751 D_keypad = 0;
3752 if (D_CCS && strcmp(D_CCS, D_CCE))
3753 AddCStr(D_CCE);
3754 D_cursorkeys = 0;
3755 #endif
3756 AddCStr(D_CE0);
3757 D_rend = mchar_null;
3758 D_atyp = 0;
3759 AddCStr(D_DS);
3760 D_hstatus = 0;
3761 AddCStr(D_VE);
3762 D_curvis = 0;
3763 ChangeScrollRegion(oldtop, oldbot);
3764 SetRendition(&oldrend);
3765 KeypadMode(oldkeypad);
3766 CursorkeysMode(oldcursorkeys);
3767 CursorVisibility(oldcurvis);
3768 MouseMode(oldmouse);
3769 if (D_CWS)
3771 debug("ResizeDisplay: using WS\n");
3772 AddCStr(tgoto(D_CWS, D_width, D_height));
3774 else if (D_CZ0 && (D_width == Z0width || D_width == Z1width))
3776 debug("ResizeDisplay: using Z0/Z1\n");
3777 AddCStr(D_width == Z0width ? D_CZ0 : D_CZ1);
3780 #endif /* AUTO_NUKE */
3782 #ifdef linux
3783 /* linux' select can't handle flow control, so wait 100ms if
3784 * we get EAGAIN
3786 static void
3787 disp_writeev_eagain(ev, data)
3788 struct event *ev;
3789 char *data;
3791 display = (struct display *)data;
3792 evdeq(&D_writeev);
3793 D_writeev.type = EV_WRITE;
3794 D_writeev.handler = disp_writeev_fn;
3795 evenq(&D_writeev);
3797 #endif
3799 static void
3800 disp_writeev_fn(ev, data)
3801 struct event *ev;
3802 char *data;
3804 int len, size = OUTPUT_BLOCK_SIZE;
3806 display = (struct display *)data;
3807 len = D_obufp - D_obuf;
3808 if (len < size)
3809 size = len;
3810 ASSERT(len >= 0);
3811 size = write(D_userfd, D_obuf, size);
3812 if (size >= 0)
3814 len -= size;
3815 if (len)
3817 bcopy(D_obuf + size, D_obuf, len);
3818 debug2("ASYNC: wrote %d - remaining %d\n", size, len);
3820 D_obufp -= size;
3821 D_obuffree += size;
3822 if (D_blocked_fuzz)
3824 D_blocked_fuzz -= size;
3825 if (D_blocked_fuzz < 0)
3826 D_blocked_fuzz = 0;
3828 if (D_blockedev.queued)
3830 if (D_obufp - D_obuf > D_obufmax / 2)
3832 debug2("%s: resetting timeout to %g secs\n", D_usertty, D_nonblock/1000.);
3833 SetTimeout(&D_blockedev, D_nonblock);
3835 else
3837 debug1("%s: deleting blocked timeout\n", D_usertty);
3838 evdeq(&D_blockedev);
3841 if (D_blocked == 1 && D_obuf == D_obufp)
3843 /* empty again, restart output */
3844 debug1("%s: buffer empty, unblocking\n", D_usertty);
3845 D_blocked = 0;
3846 Activate(D_fore ? D_fore->w_norefresh : 0);
3847 D_blocked_fuzz = D_obufp - D_obuf;
3850 else
3852 #ifdef linux
3853 /* linux flow control is badly broken */
3854 if (errno == EAGAIN)
3856 evdeq(&D_writeev);
3857 D_writeev.type = EV_TIMEOUT;
3858 D_writeev.handler = disp_writeev_eagain;
3859 SetTimeout(&D_writeev, 100);
3860 evenq(&D_writeev);
3862 #endif
3863 if (errno != EINTR && errno != EAGAIN)
3864 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3865 if (errno != EWOULDBLOCK)
3866 #endif
3867 Msg(errno, "Error writing output to display");
3871 static void
3872 disp_readev_fn(ev, data)
3873 struct event *ev;
3874 char *data;
3876 int size;
3877 char buf[IOSIZE];
3878 struct canvas *cv;
3880 display = (struct display *)data;
3882 /* Hmmmm... a bit ugly... */
3883 if (D_forecv)
3884 for (cv = D_forecv->c_layer->l_cvlist; cv; cv = cv->c_lnext)
3886 display = cv->c_display;
3887 if (D_status == STATUS_ON_WIN)
3888 RemoveStatus();
3891 display = (struct display *)data;
3892 if (D_fore == 0)
3893 size = IOSIZE;
3894 else
3896 #ifdef PSEUDOS
3897 if (W_UWP(D_fore))
3898 size = sizeof(D_fore->w_pwin->p_inbuf) - D_fore->w_pwin->p_inlen;
3899 else
3900 #endif
3901 size = sizeof(D_fore->w_inbuf) - D_fore->w_inlen;
3904 if (size > IOSIZE)
3905 size = IOSIZE;
3906 if (size <= 0)
3907 size = 1; /* Always allow one char for command keys */
3909 size = read(D_userfd, buf, size);
3910 if (size < 0)
3912 if (errno == EINTR || errno == EAGAIN)
3913 return;
3914 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3915 if (errno == EWOULDBLOCK)
3916 return;
3917 #endif
3918 debug1("Read error: %d - hangup!\n", errno);
3919 Hangup();
3920 sleep(1);
3921 return;
3923 else if (size == 0)
3925 debug("Found EOF - hangup!\n");
3926 Hangup();
3927 sleep(1);
3928 return;
3930 if (D_blocked == 4)
3932 D_blocked = 0;
3933 #ifdef BLANKER_PRG
3934 KillBlanker();
3935 #endif
3936 Activate(D_fore ? D_fore->w_norefresh : 0);
3937 ResetIdle();
3938 return;
3940 #ifdef ZMODEM
3941 if (D_blocked > 1) /* 2, 3 */
3943 char *bufp;
3944 struct win *p;
3946 flayer = 0;
3947 for (p = windows; p ; p = p->w_next)
3948 if (p->w_zdisplay == display)
3950 flayer = &p->w_layer;
3951 bufp = buf;
3952 while (size > 0)
3953 LayProcess(&bufp, &size);
3954 return;
3956 debug("zmodem window gone, deblocking display");
3957 zmodem_abort(0, display);
3959 #endif
3960 if (idletimo > 0)
3961 ResetIdle();
3962 if (D_fore)
3963 D_fore->w_lastdisp = display;
3964 if (D_mouse && D_forecv)
3966 unsigned char *bp = (unsigned char *)buf;
3967 int x, y, i = size;
3969 /* XXX this assumes that the string is read in as a whole... */
3970 for (i = size; i > 0; i--, bp++)
3972 if (i > 5 && bp[0] == 033 && bp[1] == '[' && bp[2] == 'M')
3974 bp++;
3975 i--;
3977 else if (i < 5 || bp[0] != 0233 || bp[1] != 'M')
3978 continue;
3979 x = bp[3] - 33;
3980 y = bp[4] - 33;
3981 if (x >= D_forecv->c_xs && x <= D_forecv->c_xe && y >= D_forecv->c_ys && y <= D_forecv->c_ye)
3983 x -= D_forecv->c_xoff;
3984 y -= D_forecv->c_yoff;
3985 if (x >= 0 && x < D_forecv->c_layer->l_width && y >= 0 && y < D_forecv->c_layer->l_height)
3987 bp[3] = x + 33;
3988 bp[4] = y + 33;
3989 i -= 4;
3990 bp += 4;
3991 continue;
3994 if (bp[0] == '[')
3996 bcopy((char *)bp + 1, (char *)bp, i);
3997 bp--;
3998 size--;
4000 if (i > 5)
4001 bcopy((char *)bp + 5, (char *)bp, i - 5);
4002 bp--;
4003 i -= 4;
4004 size -= 5;
4007 #ifdef ENCODINGS
4008 if (D_encoding != (D_forecv ? D_forecv->c_layer->l_encoding : 0))
4010 int i, j, c, enc;
4011 char buf2[IOSIZE * 2 + 10];
4012 enc = D_forecv ? D_forecv->c_layer->l_encoding : 0;
4013 for (i = j = 0; i < size; i++)
4015 c = ((unsigned char *)buf)[i];
4016 c = DecodeChar(c, D_encoding, &D_decodestate);
4017 if (c == -2)
4018 i--; /* try char again */
4019 if (c < 0)
4020 continue;
4021 if (pastefont)
4023 int font = 0;
4024 j += EncodeChar(buf2 + j, c, enc, &font);
4025 j += EncodeChar(buf2 + j, -1, enc, &font);
4027 else
4028 j += EncodeChar(buf2 + j, c, enc, 0);
4029 if (j > (int)sizeof(buf2) - 10) /* just in case... */
4030 break;
4032 (*D_processinput)(buf2, j);
4033 return;
4035 #endif
4036 (*D_processinput)(buf, size);
4039 static void
4040 disp_status_fn(ev, data)
4041 struct event *ev;
4042 char *data;
4044 display = (struct display *)data;
4045 debug1("disp_status_fn for display %x\n", (int)display);
4046 if (D_status)
4047 RemoveStatus();
4050 static void
4051 disp_hstatus_fn(ev, data)
4052 struct event *ev;
4053 char *data;
4055 display = (struct display *)data;
4056 if (D_status == STATUS_ON_HS)
4058 SetTimeout(ev, 1);
4059 evenq(ev);
4060 return;
4062 RefreshHStatus();
4065 static void
4066 disp_blocked_fn(ev, data)
4067 struct event *ev;
4068 char *data;
4070 struct win *p;
4072 display = (struct display *)data;
4073 debug1("blocked timeout %s\n", D_usertty);
4074 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
4076 debug("stopping output to display\n");
4077 D_blocked = 1;
4078 /* re-enable all windows */
4079 for (p = windows; p; p = p->w_next)
4080 if (p->w_readev.condneg == &D_obuflenmax)
4082 debug1("freeing window #%d\n", p->w_number);
4083 p->w_readev.condpos = p->w_readev.condneg = 0;
4088 static void
4089 cv_winid_fn(ev, data)
4090 struct event *ev;
4091 char *data;
4093 int ox, oy;
4094 struct canvas *cv = (struct canvas *)data;
4096 display = cv->c_display;
4097 if (D_status == STATUS_ON_WIN)
4099 SetTimeout(ev, 1);
4100 evenq(ev);
4101 return;
4103 ox = D_x;
4104 oy = D_y;
4105 if (cv->c_ye + 1 < D_height)
4106 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
4107 if (ox != -1 && oy != -1)
4108 GotoPos(ox, oy);
4111 #ifdef MAPKEYS
4112 static void
4113 disp_map_fn(ev, data)
4114 struct event *ev;
4115 char *data;
4117 char *p;
4118 int l, i;
4119 unsigned char *q;
4120 display = (struct display *)data;
4121 debug("Flushing map sequence\n");
4122 if (!(l = D_seql))
4123 return;
4124 p = (char *)D_seqp - l;
4125 D_seqp = D_kmaps + 3;
4126 D_seql = 0;
4127 if ((q = D_seqh) != 0)
4129 D_seqh = 0;
4130 i = q[0] << 8 | q[1];
4131 i &= ~KMAP_NOTIMEOUT;
4132 debug1("Mapping former hit #%d - ", i);
4133 debug2("%d(%s) - ", q[2], q + 3);
4134 if (StuffKey(i))
4135 ProcessInput2((char *)q + 3, q[2]);
4136 if (display == 0)
4137 return;
4138 l -= q[2];
4139 p += q[2];
4141 else
4142 D_dontmap = 1;
4143 ProcessInput(p, l);
4145 #endif
4147 static void
4148 disp_idle_fn(ev, data)
4149 struct event *ev;
4150 char *data;
4152 struct display *olddisplay;
4153 display = (struct display *)data;
4154 debug("idle timeout\n");
4155 if (idletimo <= 0 || idleaction.nr == RC_ILLEGAL)
4156 return;
4157 olddisplay = display;
4158 flayer = D_forecv->c_layer;
4159 fore = D_fore;
4160 DoAction(&idleaction, -1);
4161 if (idleaction.nr == RC_BLANKER)
4162 return;
4163 for (display = displays; display; display = display->d_next)
4164 if (olddisplay == display)
4165 break;
4166 if (display)
4167 ResetIdle();
4170 void
4171 ResetIdle()
4173 if (idletimo > 0)
4175 SetTimeout(&D_idleev, idletimo);
4176 if (!D_idleev.queued)
4177 evenq(&D_idleev);
4179 else
4180 evdeq(&D_idleev);
4184 #ifdef BLANKER_PRG
4186 static void
4187 disp_blanker_fn(ev, data)
4188 struct event *ev;
4189 char *data;
4191 char buf[IOSIZE], *b;
4192 int size;
4194 display = (struct display *)data;
4195 size = read(D_blankerev.fd, buf, IOSIZE);
4196 if (size <= 0)
4198 evdeq(&D_blankerev);
4199 close(D_blankerev.fd);
4200 D_blankerev.fd = -1;
4201 return;
4203 for (b = buf; size; size--)
4204 AddChar(*b++);
4207 void
4208 KillBlanker()
4210 int oldtop = D_top, oldbot = D_bot;
4211 struct mchar oldrend;
4213 if (D_blankerev.fd == -1)
4214 return;
4215 if (D_blocked == 4)
4216 D_blocked = 0;
4217 evdeq(&D_blankerev);
4218 close(D_blankerev.fd);
4219 D_blankerev.fd = -1;
4220 Kill(D_blankerpid, SIGHUP);
4221 D_top = D_bot = -1;
4222 oldrend = D_rend;
4223 if (D_ME)
4225 AddCStr(D_ME);
4226 AddCStr(D_ME);
4228 else
4230 #ifdef COLOR
4231 if (D_hascolor)
4232 AddStr("\033[m\033[m"); /* why is D_ME not set? */
4233 #endif
4234 AddCStr(D_SE);
4235 AddCStr(D_UE);
4237 AddCStr(D_VE);
4238 AddCStr(D_CE0);
4239 D_rend = mchar_null;
4240 D_atyp = 0;
4241 D_curvis = 0;
4242 D_x = D_y = -1;
4243 ChangeScrollRegion(oldtop, oldbot);
4244 SetRendition(&oldrend);
4245 ClearAll();
4248 void
4249 RunBlanker(cmdv)
4250 char **cmdv;
4252 char *m;
4253 int pid;
4254 int slave = -1;
4255 char termname[30];
4256 #ifndef TIOCSWINSZ
4257 char libuf[20], cobuf[20];
4258 #endif
4259 char **np;
4261 strcpy(termname, "TERM=");
4262 strncpy(termname + 5, D_termname, sizeof(termname) - 6);
4263 termname[sizeof(termname) - 1] = 0;
4264 KillBlanker();
4265 D_blankerpid = -1;
4266 if ((D_blankerev.fd = OpenPTY(&m)) == -1)
4268 Msg(0, "OpenPty failed");
4269 return;
4271 #ifdef O_NOCTTY
4272 if (pty_preopen)
4274 if ((slave = open(m, O_RDWR|O_NOCTTY)) == -1)
4276 Msg(errno, "%s", m);
4277 close(D_blankerev.fd);
4278 D_blankerev.fd = -1;
4279 return;
4282 #endif
4283 switch (pid = (int)fork())
4285 case -1:
4286 Msg(errno, "fork");
4287 close(D_blankerev.fd);
4288 D_blankerev.fd = -1;
4289 return;
4290 case 0:
4291 displays = 0;
4292 #ifdef DEBUG
4293 if (dfp && dfp != stderr)
4294 fclose(dfp);
4295 #endif
4296 if (setgid(real_gid) || setuid(real_uid))
4297 Panic(errno, "setuid/setgid");
4298 brktty(D_userfd);
4299 freetty();
4300 close(0);
4301 close(1);
4302 close(2);
4303 closeallfiles(slave);
4304 if (open(m, O_RDWR))
4305 Panic(errno, "Cannot open %s", m);
4306 dup(0);
4307 dup(0);
4308 if (slave != -1)
4309 close(slave);
4310 InitPTY(0);
4311 fgtty(0);
4312 SetTTY(0, &D_OldMode);
4313 np = NewEnv + 3;
4314 *np++ = NewEnv[0];
4315 *np++ = termname;
4316 #ifdef TIOCSWINSZ
4317 glwz.ws_col = D_width;
4318 glwz.ws_row = D_height;
4319 (void)ioctl(0, TIOCSWINSZ, (char *)&glwz);
4320 #else
4321 sprintf(libuf, "LINES=%d", D_height);
4322 sprintf(libuf, "COLUMNS=%d", D_width);
4323 *np++ = libuf;
4324 *np++ = cobuf;
4325 #endif
4326 #ifdef SIGPIPE
4327 signal(SIGPIPE, SIG_DFL);
4328 #endif
4329 display = 0;
4330 execvpe(*cmdv, cmdv, NewEnv + 3);
4331 Panic(errno, *cmdv);
4332 default:
4333 break;
4335 D_blankerpid = pid;
4336 evenq(&D_blankerev);
4337 D_blocked = 4;
4338 ClearAll();
4341 #endif
4343 struct layout *layouts;
4344 struct layout *laytab[MAXLAY];
4345 struct layout *layout_last, layout_last_marker;
4346 struct layout *layout_attach = &layout_last_marker;
4348 void
4349 FreeLayoutCv(cv)
4350 struct canvas *cv;
4352 for (; cv; cv = cv->c_slnext)
4353 if (cv->c_slperp)
4355 FreeLayoutCv(cv->c_slperp);
4356 free(cv->c_slperp);
4357 cv->c_slperp = 0;
4361 void
4362 DupLayoutCv(cvf, cvt, save)
4363 struct canvas *cvf, *cvt;
4364 int save;
4366 while(cvf)
4368 cvt->c_slorient = cvf->c_slorient;
4369 cvt->c_slweight = cvf->c_slweight;
4370 if (cvf == D_forecv)
4371 D_forecv = cvt;
4372 if (!save)
4374 cvt->c_display = display;
4375 if (!cvf->c_slperp)
4377 cvt->c_captev.type = EV_TIMEOUT;
4378 cvt->c_captev.data = (char *)cvt;
4379 cvt->c_captev.handler = cv_winid_fn;
4380 cvt->c_blank.l_cvlist = 0;
4381 cvt->c_blank.l_layfn = &BlankLf;
4382 cvt->c_blank.l_bottom = &cvt->c_blank;
4384 cvt->c_layer = cvf->c_layer;
4386 else
4388 struct win *p = cvf->c_layer ? Layer2Window(cvf->c_layer) : 0;
4389 cvt->c_layer = p ? &p->w_layer : 0;
4391 if (cvf->c_slperp)
4393 cvt->c_slperp = (struct canvas *)calloc(1, sizeof(struct canvas));
4394 cvt->c_slperp->c_slback = cvt;
4395 DupLayoutCv(cvf->c_slperp, cvt->c_slperp, save);
4397 if (cvf->c_slnext)
4399 cvt->c_slnext = (struct canvas *)calloc(1, sizeof(struct canvas));
4400 cvt->c_slnext->c_slprev = cvt;
4401 cvt->c_slnext->c_slback = cvt->c_slback;
4403 cvf = cvf->c_slnext;
4404 cvt = cvt->c_slnext;
4408 void
4409 PutWindowCv(cv)
4410 struct canvas *cv;
4412 struct win *p;
4413 for (; cv; cv = cv->c_slnext)
4415 if (cv->c_slperp)
4417 PutWindowCv(cv->c_slperp);
4418 continue;
4420 p = cv->c_layer ? (struct win *)cv->c_layer->l_data : 0;
4421 cv->c_layer = 0;
4422 SetCanvasWindow(cv, p);
4426 struct layout *
4427 CreateLayout(title, startat)
4428 char *title;
4429 int startat;
4431 struct layout *lay;
4432 int i;
4434 if (startat >= MAXLAY || startat < 0)
4435 startat = 0;
4436 for (i = startat; ;)
4438 if (!laytab[i])
4439 break;
4440 if (++i == MAXLAY)
4441 i = 0;
4442 if (i == startat)
4444 Msg(0, "No more layouts\n");
4445 return 0;
4448 lay = (struct layout *)calloc(1, sizeof(*lay));
4449 lay->lay_title = SaveStr(title);
4450 lay->lay_autosave = 1;
4451 lay->lay_number = i;
4452 laytab[i] = lay;
4453 lay->lay_next = layouts;
4454 layouts = lay;
4455 return lay;
4458 void
4459 SaveLayout(name, cv)
4460 char *name;
4461 struct canvas *cv;
4463 struct layout *lay;
4464 struct canvas *fcv;
4465 for (lay = layouts; lay; lay = lay->lay_next)
4466 if (!strcmp(lay->lay_title, name))
4467 break;
4468 if (lay)
4469 FreeLayoutCv(&lay->lay_canvas);
4470 else
4471 lay = CreateLayout(name, 0);
4472 if (!lay)
4473 return;
4474 fcv = D_forecv;
4475 DupLayoutCv(cv, &lay->lay_canvas, 1);
4476 lay->lay_forecv = D_forecv;
4477 D_forecv = fcv;
4478 D_layout = lay;
4481 void
4482 AutosaveLayout(lay)
4483 struct layout *lay;
4485 struct canvas *fcv;
4486 if (!lay || !lay->lay_autosave)
4487 return;
4488 FreeLayoutCv(&lay->lay_canvas);
4489 fcv = D_forecv;
4490 DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
4491 lay->lay_forecv = D_forecv;
4492 D_forecv = fcv;
4495 struct layout *
4496 FindLayout(name)
4497 char *name;
4499 struct layout *lay;
4500 char *s;
4501 int i;
4502 for (i = 0, s = name; *s >= '0' && *s <= '9'; s++)
4503 i = i * 10 + (*s - '0');
4504 if (!*s && s != name && i >= 0 && i < MAXLAY)
4505 return laytab[i];
4506 for (lay = layouts; lay; lay = lay->lay_next)
4507 if (!strcmp(lay->lay_title, name))
4508 break;
4509 return lay;
4512 void
4513 LoadLayout(lay, cv)
4514 struct layout *lay;
4515 struct canvas *cv;
4517 AutosaveLayout(D_layout);
4518 if (!lay)
4520 while (D_canvas.c_slperp)
4521 FreeCanvas(D_canvas.c_slperp);
4522 MakeDefaultCanvas();
4523 SetCanvasWindow(D_forecv, 0);
4524 D_layout = 0;
4525 return;
4527 while (D_canvas.c_slperp)
4528 FreeCanvas(D_canvas.c_slperp);
4529 D_cvlist = 0;
4530 D_forecv = lay->lay_forecv;
4531 DupLayoutCv(&lay->lay_canvas, &D_canvas, 0);
4532 D_canvas.c_ye = D_height - 1 - ((D_canvas.c_slperp && D_canvas.c_slperp->c_slnext) || captionalways) - (D_has_hstatus == HSTATUS_LASTLINE);
4533 ResizeCanvas(&D_canvas);
4534 RecreateCanvasChain();
4535 RethinkDisplayViewports();
4536 PutWindowCv(&D_canvas);
4537 ResizeLayersToCanvases();
4538 D_layout = lay;
4541 void
4542 NewLayout(title, startat)
4543 char *title;
4544 int startat;
4546 struct layout *lay;
4547 struct canvas *fcv;
4549 lay = CreateLayout(title, startat);
4550 if (!lay)
4551 return;
4552 LoadLayout(0, &D_canvas);
4553 fcv = D_forecv;
4554 DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
4555 lay->lay_forecv = D_forecv;
4556 D_forecv = fcv;
4557 D_layout = lay;
4558 lay->lay_autosave = 1;
4561 static char *
4562 AddLayoutsInfo(buf, len, where)
4563 char *buf;
4564 int len;
4565 int where;
4567 char *s, *ss, *t;
4568 struct layout *p, **pp;
4569 int l;
4571 s = ss = buf;
4572 for (pp = laytab; pp < laytab + MAXLAY; pp++)
4574 if (pp - laytab == where && ss == buf)
4575 ss = s;
4576 if ((p = *pp) == 0)
4577 continue;
4578 t = p->lay_title;
4579 l = strlen(t);
4580 if (l > 20)
4581 l = 20;
4582 if (s - buf + l > len - 24)
4583 break;
4584 if (s > buf)
4586 *s++ = ' ';
4587 *s++ = ' ';
4589 sprintf(s, "%d", p->lay_number);
4590 if (p->lay_number == where)
4591 ss = s;
4592 s += strlen(s);
4593 if (display && p == D_layout)
4594 *s++ = '*';
4595 *s++ = ' ';
4596 strncpy(s, t, l);
4597 s += l;
4599 *s = 0;
4600 return ss;
4603 void
4604 ShowLayouts(where)
4605 int where;
4607 char buf[1024];
4608 char *s, *ss;
4610 if (!display)
4611 return;
4612 if (!layouts)
4614 Msg(0, "No layouts defined\n");
4615 return;
4617 if (where == -1 && D_layout)
4618 where = D_layout->lay_number;
4619 ss = AddLayoutsInfo(buf, sizeof(buf), where);
4620 s = buf + strlen(buf);
4621 if (ss - buf > D_width / 2)
4623 ss -= D_width / 2;
4624 if (s - ss < D_width)
4626 ss = s - D_width;
4627 if (ss < buf)
4628 ss = buf;
4631 else
4632 ss = buf;
4633 Msg(0, "%s", ss);