Start converting to GPL v3+ (ref: ticket #23900)
[screen-lua.git] / src / display.c
blobf4e272ddf40d91f7a2b65c0e7649478fe2171259
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 3, 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, see
18 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 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;
415 static void
416 CanvasInitBlank(cv)
417 struct canvas *cv;
419 cv->c_blank.l_cvlist = cv;
420 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
421 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
422 cv->c_blank.l_x = cv->c_blank.l_y = 0;
423 cv->c_blank.l_layfn = &BlankLf;
424 cv->c_blank.l_data = 0;
425 cv->c_blank.l_next = 0;
426 cv->c_blank.l_bottom = &cv->c_blank;
427 cv->c_blank.l_blocking = 0;
428 cv->c_layer = &cv->c_blank;
432 MakeDefaultCanvas()
434 struct canvas *cv;
436 ASSERT(display);
437 if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
438 return -1;
439 cv->c_xs = 0;
440 cv->c_xe = D_width - 1;
441 cv->c_ys = 0;
442 cv->c_ye = D_height - 1 - (D_has_hstatus == HSTATUS_LASTLINE) - captionalways;
443 debug2("MakeDefaultCanvas 0,0 %d,%d\n", cv->c_xe, cv->c_ye);
444 cv->c_xoff = 0;
445 cv->c_yoff = 0;
446 cv->c_next = 0;
447 cv->c_display = display;
448 cv->c_vplist = 0;
449 cv->c_slnext = 0;
450 cv->c_slprev = 0;
451 cv->c_slperp = 0;
452 cv->c_slweight = 1;
453 cv->c_slback = &D_canvas;
454 D_canvas.c_slperp = cv;
455 D_canvas.c_xs = cv->c_xs;
456 D_canvas.c_xe = cv->c_xe;
457 D_canvas.c_ys = cv->c_ys;
458 D_canvas.c_ye = cv->c_ye;
459 cv->c_slorient = SLICE_UNKN;
460 cv->c_captev.type = EV_TIMEOUT;
461 cv->c_captev.data = (char *)cv;
462 cv->c_captev.handler = cv_winid_fn;
464 CanvasInitBlank(cv);
465 cv->c_lnext = 0;
467 D_cvlist = cv;
468 RethinkDisplayViewports();
469 D_forecv = cv; /* default input focus */
470 return 0;
473 static struct canvas **
474 CreateCanvasChainRec(cv, cvp)
475 struct canvas *cv;
476 struct canvas **cvp;
478 for (; cv; cv = cv->c_slnext)
480 if (cv->c_slperp)
481 cvp = CreateCanvasChainRec(cv->c_slperp, cvp);
482 else
484 *cvp = cv;
485 cvp = &cv->c_next;
488 return cvp;
491 void
492 RecreateCanvasChain()
494 struct canvas **cvp;
495 cvp = CreateCanvasChainRec(D_canvas.c_slperp, &D_cvlist);
496 *cvp = 0;
499 static void
500 FreeCanvas(cv)
501 struct canvas *cv;
503 struct viewport *vp, *nvp;
504 struct canvas **cvp;
505 struct win *p;
507 if (cv->c_slprev)
508 cv->c_slprev->c_slnext = cv->c_slnext;
509 if (cv->c_slnext)
510 cv->c_slnext->c_slprev = cv->c_slprev;
511 if (cv->c_slback && cv->c_slback->c_slperp == cv)
512 cv->c_slback->c_slperp = cv->c_slnext ? cv->c_slnext : cv->c_slprev;
513 if (cv->c_slperp)
515 while (cv->c_slperp)
516 FreeCanvas(cv->c_slperp);
517 free(cv);
518 return;
521 if (display)
523 if (D_forecv == cv)
524 D_forecv = 0;
525 /* remove from canvas chain as SetCanvasWindow might call
526 * some layer function */
527 for (cvp = &D_cvlist; *cvp ; cvp = &(*cvp)->c_next)
528 if (*cvp == cv)
530 *cvp = cv->c_next;
531 break;
534 p = cv->c_layer ? Layer2Window(cv->c_layer) : 0;
535 SetCanvasWindow(cv, 0);
536 if (p)
537 WindowChanged(p, 'u');
538 if (flayer == cv->c_layer)
539 flayer = 0;
540 for (vp = cv->c_vplist; vp; vp = nvp)
542 vp->v_canvas = 0;
543 nvp = vp->v_next;
544 vp->v_next = 0;
545 free(vp);
547 evdeq(&cv->c_captev);
548 free(cv);
552 CountCanvas(cv)
553 struct canvas *cv;
555 int num = 0;
556 for (; cv; cv = cv->c_slnext)
558 if (cv->c_slperp)
560 struct canvas *cvp;
561 int nump = 1, n;
562 for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
563 if (cvp->c_slperp)
565 n = CountCanvas(cvp->c_slperp);
566 if (n > nump)
567 nump = n;
569 num += nump;
571 else
572 num++;
574 return num;
578 CountCanvasPerp(cv)
579 struct canvas *cv;
581 struct canvas *cvp;
582 int num = 1, n;
583 for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
584 if (cvp->c_slperp)
586 n = CountCanvas(cvp->c_slperp);
587 if (n > num)
588 num = n;
590 return num;
593 void
594 EqualizeCanvas(cv, gflag)
595 struct canvas *cv;
596 int gflag;
598 struct canvas *cv2;
599 for (; cv; cv = cv->c_slnext)
601 if (cv->c_slperp && gflag)
603 cv->c_slweight = CountCanvasPerp(cv);
604 for (cv2 = cv->c_slperp; cv2; cv2 = cv2->c_slnext)
605 if (cv2->c_slperp)
606 EqualizeCanvas(cv2->c_slperp, gflag);
608 else
609 cv->c_slweight = 1;
613 void
614 ResizeCanvas(cv)
615 struct canvas *cv;
617 struct canvas *cv2, *cvn, *fcv;
618 int nh, i, maxi, hh, m, w, wsum;
619 int need, got;
620 int xs, ys, xe, ye;
621 int focusmin = 0;
623 xs = cv->c_xs;
624 ys = cv->c_ys;
625 xe = cv->c_xe;
626 ye = cv->c_ye;
627 cv = cv->c_slperp;
628 debug2("ResizeCanvas: %d,%d", xs, ys);
629 debug2(" %d,%d\n", xe, ye);
630 if (cv == 0)
631 return;
632 if (cv->c_slorient == SLICE_UNKN)
634 ASSERT(!cv->c_slnext && !cv->c_slperp);
635 cv->c_xs = xs;
636 cv->c_xe = xe;
637 cv->c_ys = ys;
638 cv->c_ye = ye;
639 cv->c_xoff = cv->c_xs;
640 cv->c_yoff = cv->c_ys;
641 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
642 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
643 return;
646 fcv = 0;
647 if (focusminwidth || focusminheight)
649 debug("searching for focus canvas\n");
650 cv2 = D_forecv;
651 while (cv2->c_slback)
653 if (cv2->c_slback == cv->c_slback)
655 fcv = cv2;
656 focusmin = cv->c_slorient == SLICE_VERT ? focusminheight : focusminwidth;
657 if (focusmin > 0)
658 focusmin--;
659 else if (focusmin < 0)
660 focusmin = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
661 debug1("found, focusmin=%d\n", focusmin);
663 cv2 = cv2->c_slback;
666 if (focusmin)
668 m = CountCanvas(cv) * 2;
669 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
670 nh -= m;
671 if (nh < 0)
672 nh = 0;
673 if (focusmin > nh)
674 focusmin = nh;
675 debug1("corrected to %d\n", focusmin);
678 /* pass 1: calculate weight sum */
679 for (cv2 = cv, wsum = 0; cv2; cv2 = cv2->c_slnext)
681 debug1(" weight %d\n", cv2->c_slweight);
682 wsum += cv2->c_slweight;
684 debug1("wsum = %d\n", wsum);
685 if (wsum == 0)
686 wsum = 1;
687 w = wsum;
689 /* pass 2: calculate need/excess space */
690 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
691 for (cv2 = cv, need = got = 0; cv2; cv2 = cv2->c_slnext)
693 m = cv2->c_slperp ? CountCanvasPerp(cv2) * 2 - 1 : 1;
694 if (cv2 == fcv)
695 m += focusmin;
696 hh = cv2->c_slweight ? nh * cv2->c_slweight / w : 0;
697 w -= cv2->c_slweight;
698 nh -= hh;
699 debug2(" should %d min %d\n", hh, m);
700 if (hh <= m + 1)
701 need += m + 1 - hh;
702 else
703 got += hh - m - 1;
705 debug2("need: %d, got %d\n", need, got);
706 if (need > got)
707 need = got;
709 /* pass 3: distribute space */
710 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
711 i = cv->c_slorient == SLICE_VERT ? ys : xs;
712 maxi = cv->c_slorient == SLICE_VERT ? ye : xe;
713 w = wsum;
714 for (; cv; cv = cvn)
716 cvn = cv->c_slnext;
717 if (i > maxi)
719 if (cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slprev->c_slperp && !cv->c_slprev->c_slprev)
721 cv->c_slprev->c_slorient = SLICE_UNKN;
722 if (!captionalways)
724 cv->c_slback->c_ye++;
725 cv->c_slprev->c_ye++;
728 SetCanvasWindow(cv, 0);
729 FreeCanvas(cv);
730 continue;
732 m = cv->c_slperp ? CountCanvasPerp(cv) * 2 - 1 : 1;
733 if (cv == fcv)
734 m += focusmin;
735 hh = cv->c_slweight ? nh * cv->c_slweight / w : 0;
736 w -= cv->c_slweight;
737 nh -= hh;
738 debug2(" should %d min %d\n", hh, m);
739 if (hh <= m + 1)
741 hh = m + 1;
742 debug1(" -> %d\n", hh);
744 else
746 int hx = need * (hh - m - 1) / got;
747 debug3(" -> %d - %d = %d\n", hh, hx, hh - hx);
748 got -= (hh - m - 1);
749 hh -= hx;
750 need -= hx;
751 debug2(" now need=%d got=%d\n", need, got);
753 ASSERT(hh >= m + 1);
754 /* hh is window size plus pation line */
755 if (i + hh > maxi + 2)
757 hh = maxi + 2 - i;
758 debug1(" not enough space, reducing to %d\n", hh);
760 if (i + hh == maxi + 1)
762 hh++;
763 debug(" incrementing as no other canvas will fit\n");
765 if (cv->c_slorient == SLICE_VERT)
767 cv->c_xs = xs;
768 cv->c_xe = xe;
769 cv->c_ys = i;
770 cv->c_ye = i + hh - 2;
771 cv->c_xoff = xs;
772 cv->c_yoff = i;
774 else
776 cv->c_xs = i;
777 cv->c_xe = i + hh - 2;
778 cv->c_ys = ys;
779 cv->c_ye = ye;
780 cv->c_xoff = i;
781 cv->c_yoff = ys;
783 cv->c_xoff = cv->c_xs;
784 cv->c_yoff = cv->c_ys;
785 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
786 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
787 if (cv->c_slperp)
789 ResizeCanvas(cv);
790 if (!cv->c_slperp->c_slnext)
792 debug("deleting perp node\n");
793 FreePerp(cv->c_slperp);
794 FreePerp(cv);
797 i += hh;
801 static struct canvas *
802 AddPerp(cv)
803 struct canvas *cv;
805 struct canvas *pcv;
806 debug("Creating new perp node\n");
808 if ((pcv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
809 return 0;
810 pcv->c_next = 0;
811 pcv->c_display = cv->c_display;
812 pcv->c_slnext = cv->c_slnext;
813 pcv->c_slprev = cv->c_slprev;
814 pcv->c_slperp = cv;
815 pcv->c_slback = cv->c_slback;
816 if (cv->c_slback && cv->c_slback->c_slperp == cv)
817 cv->c_slback->c_slperp = pcv;
818 pcv->c_slorient = cv->c_slorient;
819 pcv->c_xoff = 0;
820 pcv->c_yoff = 0;
821 pcv->c_xs = cv->c_xs;
822 pcv->c_xe = cv->c_xe;
823 pcv->c_ys = cv->c_ys;
824 pcv->c_ye = cv->c_ye;
825 if (pcv->c_slnext)
826 pcv->c_slnext->c_slprev = pcv;
827 if (pcv->c_slprev)
828 pcv->c_slprev->c_slnext = pcv;
829 pcv->c_slweight = cv->c_slweight;
830 CanvasInitBlank(pcv);
831 cv->c_slweight = 1;
832 cv->c_slnext = 0;
833 cv->c_slprev = 0;
834 cv->c_slperp = 0;
835 cv->c_slback = pcv;
836 cv->c_slorient = SLICE_UNKN;
837 return pcv;
840 static void
841 FreePerp(pcv)
842 struct canvas *pcv;
844 struct canvas *cv;
846 if (!pcv->c_slperp)
847 return;
848 cv = pcv->c_slperp;
849 cv->c_slprev = pcv->c_slprev;
850 if (cv->c_slprev)
851 cv->c_slprev->c_slnext = cv;
852 cv->c_slback = pcv->c_slback;
853 if (cv->c_slback && cv->c_slback->c_slperp == pcv)
854 cv->c_slback->c_slperp = cv;
855 cv->c_slorient = pcv->c_slorient;
856 cv->c_slweight = pcv->c_slweight;
857 while (cv->c_slnext)
859 cv = cv->c_slnext;
860 cv->c_slorient = pcv->c_slorient;
861 cv->c_slback = pcv->c_slback;
862 cv->c_slweight = pcv->c_slweight;
864 cv->c_slnext = pcv->c_slnext;
865 if (cv->c_slnext)
866 cv->c_slnext->c_slprev = cv;
867 free(pcv);
871 AddCanvas(orient)
872 int orient;
874 struct canvas *cv;
875 int xs, xe, ys, ye;
876 int h, num;
878 cv = D_forecv;
879 debug2("AddCanvas orient %d, forecv is %d\n", orient, cv->c_slorient);
881 if (cv->c_slorient != SLICE_UNKN && cv->c_slorient != orient)
882 if (!AddPerp(cv))
883 return -1;
885 cv = D_forecv;
886 xs = cv->c_slback->c_xs;
887 xe = cv->c_slback->c_xe;
888 ys = cv->c_slback->c_ys;
889 ye = cv->c_slback->c_ye;
890 if (!captionalways && cv == D_canvas.c_slperp && !cv->c_slnext)
891 ye--; /* need space for caption */
892 debug2("Adding Canvas to slice %d,%d ", xs, ys);
893 debug2("%d,%d\n", xe, ye);
895 num = CountCanvas(cv->c_slback->c_slperp) + 1;
896 debug1("Num = %d\n", num);
897 if (orient == SLICE_VERT)
898 h = ye - ys + 1;
899 else
900 h = xe - xs + 1;
902 h -= 2 * num - 1;
903 if (h < 0)
904 return -1; /* can't fit in */
906 if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
907 return -1;
909 D_forecv->c_slback->c_ye = ye; /* in case we modified it above */
910 D_forecv->c_slorient = orient; /* in case it was UNKN */
911 cv->c_slnext = D_forecv->c_slnext;
912 cv->c_slprev = D_forecv;
913 D_forecv->c_slnext = cv;
914 if (cv->c_slnext)
915 cv->c_slnext->c_slprev = cv;
916 cv->c_slorient = orient;
917 cv->c_slback = D_forecv->c_slback;
919 cv->c_xs = xs;
920 cv->c_xe = xe;
921 cv->c_ys = ys;
922 cv->c_ye = ye;
923 cv->c_xoff = 0;
924 cv->c_yoff = 0;
925 cv->c_display = display;
926 cv->c_vplist = 0;
927 cv->c_captev.type = EV_TIMEOUT;
928 cv->c_captev.data = (char *)cv;
929 cv->c_captev.handler = cv_winid_fn;
931 CanvasInitBlank(cv);
932 cv->c_lnext = 0;
934 cv->c_next = 0;
936 cv = cv->c_slback;
937 EqualizeCanvas(cv->c_slperp, 0);
938 ResizeCanvas(cv);
939 RecreateCanvasChain();
940 RethinkDisplayViewports();
941 ResizeLayersToCanvases();
942 return 0;
945 void
946 RemCanvas()
948 int xs, xe, ys, ye;
949 struct canvas *cv;
951 debug("RemCanvas\n");
952 cv = D_forecv;
953 if (cv->c_slorient == SLICE_UNKN)
954 return;
955 while (cv->c_slprev)
956 cv = cv->c_slprev;
957 if (!cv->c_slnext)
958 return;
959 if (!cv->c_slnext->c_slnext && cv->c_slback->c_slback)
961 /* two canvases in slice, kill perp node */
962 cv = D_forecv;
963 debug("deleting perp node\n");
964 FreePerp(cv->c_slprev ? cv->c_slprev : cv->c_slnext);
965 FreePerp(cv->c_slback);
967 xs = cv->c_slback->c_xs;
968 xe = cv->c_slback->c_xe;
969 ys = cv->c_slback->c_ys;
970 ye = cv->c_slback->c_ye;
971 /* free canvas */
972 cv = D_forecv;
973 D_forecv = cv->c_slprev;
974 if (!D_forecv)
975 D_forecv = cv->c_slnext;
976 FreeCanvas(cv);
978 cv = D_forecv;
979 while (D_forecv->c_slperp)
980 D_forecv = D_forecv->c_slperp;
982 /* if only one canvas left, set orient back to unknown */
983 if (!cv->c_slnext && !cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slperp)
985 cv->c_slorient = SLICE_UNKN;
986 if (!captionalways)
987 cv->c_slback->c_ye = ++ye; /* caption line no longer needed */
989 cv = cv->c_slback;
990 EqualizeCanvas(cv->c_slperp, 0);
991 ResizeCanvas(cv);
993 D_fore = Layer2Window(D_forecv->c_layer);
994 flayer = D_forecv->c_layer;
996 RecreateCanvasChain();
997 RethinkDisplayViewports();
998 ResizeLayersToCanvases();
1001 void
1002 OneCanvas()
1004 struct canvas *cv = D_forecv, *ocv = 0;
1006 if (cv->c_slprev)
1008 ocv = cv->c_slprev;
1009 cv->c_slprev->c_slnext = cv->c_slnext;
1011 if (cv->c_slnext)
1013 ocv = cv->c_slnext;
1014 cv->c_slnext->c_slprev = cv->c_slprev;
1016 if (!ocv)
1017 return;
1018 if (cv->c_slback && cv->c_slback->c_slperp == cv)
1019 cv->c_slback->c_slperp = ocv;
1020 cv->c_slorient = SLICE_UNKN;
1021 while (D_canvas.c_slperp)
1022 FreeCanvas(D_canvas.c_slperp);
1023 cv = D_forecv;
1024 D_canvas.c_slperp = cv;
1025 cv->c_slback = &D_canvas;
1026 cv->c_slnext = 0;
1027 cv->c_slprev = 0;
1028 ASSERT(!cv->c_slperp);
1029 if (!captionalways)
1030 D_canvas.c_ye++; /* caption line no longer needed */
1031 ResizeCanvas(&D_canvas);
1032 RecreateCanvasChain();
1033 RethinkDisplayViewports();
1034 ResizeLayersToCanvases();
1038 RethinkDisplayViewports()
1040 struct canvas *cv;
1041 struct viewport *vp, *vpn;
1043 /* free old viewports */
1044 for (cv = display->d_cvlist; cv; cv = cv->c_next)
1046 for (vp = cv->c_vplist; vp; vp = vpn)
1048 vp->v_canvas = 0;
1049 vpn = vp->v_next;
1050 bzero((char *)vp, sizeof(*vp));
1051 free(vp);
1053 cv->c_vplist = 0;
1055 display->d_vpxmin = -1;
1056 display->d_vpxmax = -1;
1058 for (cv = display->d_cvlist; cv; cv = cv->c_next)
1060 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1061 return -1;
1062 #ifdef HOLE
1063 vp->v_canvas = cv;
1064 vp->v_xs = cv->c_xs;
1065 vp->v_ys = (cv->c_ys + cv->c_ye) / 2;
1066 vp->v_xe = cv->c_xe;
1067 vp->v_ye = cv->c_ye;
1068 vp->v_xoff = cv->c_xoff;
1069 vp->v_yoff = cv->c_yoff;
1070 vp->v_next = cv->c_vplist;
1071 cv->c_vplist = vp;
1073 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1074 return -1;
1075 vp->v_canvas = cv;
1076 vp->v_xs = (cv->c_xs + cv->c_xe) / 2;
1077 vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
1078 vp->v_xe = cv->c_xe;
1079 vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
1080 vp->v_xoff = cv->c_xoff;
1081 vp->v_yoff = cv->c_yoff;
1082 vp->v_next = cv->c_vplist;
1083 cv->c_vplist = vp;
1085 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1086 return -1;
1087 vp->v_canvas = cv;
1088 vp->v_xs = cv->c_xs;
1089 vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
1090 vp->v_xe = (3 * cv->c_xs + cv->c_xe) / 4 - 1;
1091 vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
1092 vp->v_xoff = cv->c_xoff;
1093 vp->v_yoff = cv->c_yoff;
1094 vp->v_next = cv->c_vplist;
1095 cv->c_vplist = vp;
1097 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1098 return -1;
1099 vp->v_canvas = cv;
1100 vp->v_xs = cv->c_xs;
1101 vp->v_ys = cv->c_ys;
1102 vp->v_xe = cv->c_xe;
1103 vp->v_ye = (3 * cv->c_ys + cv->c_ye) / 4 - 1;
1104 vp->v_xoff = cv->c_xoff;
1105 vp->v_yoff = cv->c_yoff;
1106 vp->v_next = cv->c_vplist;
1107 cv->c_vplist = vp;
1108 #else
1109 vp->v_canvas = cv;
1110 vp->v_xs = cv->c_xs;
1111 vp->v_ys = cv->c_ys;
1112 vp->v_xe = cv->c_xe;
1113 vp->v_ye = cv->c_ye;
1114 vp->v_xoff = cv->c_xoff;
1115 vp->v_yoff = cv->c_yoff;
1116 vp->v_next = cv->c_vplist;
1117 cv->c_vplist = vp;
1118 #endif
1120 if (cv->c_xs < display->d_vpxmin || display->d_vpxmin == -1)
1121 display->d_vpxmin = cv->c_xs;
1122 if (cv->c_xe > display->d_vpxmax || display->d_vpxmax == -1)
1123 display->d_vpxmax = cv->c_xe;
1125 return 0;
1128 void
1129 RethinkViewportOffsets(cv)
1130 struct canvas *cv;
1132 struct viewport *vp;
1134 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1136 vp->v_xoff = cv->c_xoff;
1137 vp->v_yoff = cv->c_yoff;
1142 * if the adaptflag is on, we keep the size of this display, else
1143 * we may try to restore our old window sizes.
1145 void
1146 InitTerm(adapt)
1147 int adapt;
1149 ASSERT(display);
1150 ASSERT(D_tcinited);
1151 D_top = D_bot = -1;
1152 AddCStr(D_TI);
1153 AddCStr(D_IS);
1154 /* Check for toggle */
1155 if (D_IM && strcmp(D_IM, D_EI))
1156 AddCStr(D_EI);
1157 D_insert = 0;
1158 #ifdef MAPKEYS
1159 AddCStr(D_KS);
1160 AddCStr(D_CCS);
1161 #else
1162 /* Check for toggle */
1163 if (D_KS && strcmp(D_KS, D_KE))
1164 AddCStr(D_KE);
1165 if (D_CCS && strcmp(D_CCS, D_CCE))
1166 AddCStr(D_CCE);
1167 #endif
1168 D_keypad = 0;
1169 D_cursorkeys = 0;
1170 AddCStr(D_ME);
1171 AddCStr(D_EA);
1172 AddCStr(D_CE0);
1173 D_rend = mchar_null;
1174 D_atyp = 0;
1175 if (adapt == 0)
1176 ResizeDisplay(D_defwidth, D_defheight);
1177 ChangeScrollRegion(0, D_height - 1);
1178 D_x = D_y = 0;
1179 Flush();
1180 ClearAll();
1181 debug1("we %swant to adapt all our windows to the display\n",
1182 (adapt) ? "" : "don't ");
1183 /* In case the size was changed by a init sequence */
1184 CheckScreenSize((adapt) ? 2 : 0);
1187 void
1188 FinitTerm()
1190 ASSERT(display);
1191 #ifdef BLANKER_PRG
1192 KillBlanker();
1193 #endif
1194 if (D_tcinited)
1196 ResizeDisplay(D_defwidth, D_defheight);
1197 InsertMode(0);
1198 ChangeScrollRegion(0, D_height - 1);
1199 KeypadMode(0);
1200 CursorkeysMode(0);
1201 CursorVisibility(0);
1202 MouseMode(0);
1203 SetRendition(&mchar_null);
1204 SetFlow(FLOW_NOW);
1205 #ifdef MAPKEYS
1206 AddCStr(D_KE);
1207 AddCStr(D_CCE);
1208 #endif
1209 if (D_hstatus)
1210 ShowHStatus((char *)0);
1211 #ifdef RXVT_OSC
1212 ClearAllXtermOSC();
1213 #endif
1214 D_x = D_y = -1;
1215 GotoPos(0, D_height - 1);
1216 AddChar('\r');
1217 AddChar('\n');
1218 AddCStr(D_TE);
1220 Flush();
1224 static void
1225 INSERTCHAR(c)
1226 int c;
1228 ASSERT(display);
1229 if (!D_insert && D_x < D_width - 1)
1231 if (D_IC || D_CIC)
1233 if (D_IC)
1234 AddCStr(D_IC);
1235 else
1236 AddCStr2(D_CIC, 1);
1237 RAW_PUTCHAR(c);
1238 return;
1240 InsertMode(1);
1241 if (!D_insert)
1243 RefreshLine(D_y, D_x, D_width-1, 0);
1244 return;
1247 RAW_PUTCHAR(c);
1250 void
1251 PUTCHAR(c)
1252 int c;
1254 ASSERT(display);
1255 if (D_insert && D_x < D_width - 1)
1256 InsertMode(0);
1257 RAW_PUTCHAR(c);
1260 void
1261 PUTCHARLP(c)
1262 int c;
1264 if (D_x < D_width - 1)
1266 if (D_insert)
1267 InsertMode(0);
1268 RAW_PUTCHAR(c);
1269 return;
1271 if (D_CLP || D_y != D_bot)
1273 int y = D_y;
1274 RAW_PUTCHAR(c);
1275 if (D_AM && !D_CLP)
1276 GotoPos(D_width - 1, y);
1277 return;
1279 debug("PUTCHARLP: lp_missing!\n");
1280 D_lp_missing = 1;
1281 D_rend.image = c;
1282 D_lpchar = D_rend;
1283 #ifdef DW_CHARS
1284 /* XXX -> PutChar ? */
1285 if (D_mbcs)
1287 D_lpchar.mbcs = c;
1288 D_lpchar.image = D_mbcs;
1289 D_mbcs = 0;
1290 D_x--;
1292 #endif
1296 * RAW_PUTCHAR() is for all text that will be displayed.
1297 * NOTE: charset Nr. 0 has a conversion table, but c1, c2, ... don't.
1300 STATIC void
1301 RAW_PUTCHAR(c)
1302 int c;
1304 ASSERT(display);
1306 #ifdef FONT
1307 # ifdef UTF8
1308 if (D_encoding == UTF8)
1310 c = (c & 255) | (unsigned char)D_rend.font << 8;
1311 # ifdef DW_CHARS
1312 if (D_mbcs)
1314 c = D_mbcs;
1315 if (D_x == D_width)
1316 D_x += D_AM ? 1 : -1;
1317 D_mbcs = 0;
1319 else if (utf8_isdouble(c))
1321 D_mbcs = c;
1322 D_x++;
1323 return;
1325 # endif
1326 if (c < 32)
1328 AddCStr2(D_CS0, '0');
1329 AddChar(c + 0x5f);
1330 AddCStr(D_CE0);
1331 goto addedutf8;
1333 AddUtf8(c);
1334 goto addedutf8;
1336 # endif
1337 # ifdef DW_CHARS
1338 if (is_dw_font(D_rend.font))
1340 int t = c;
1341 if (D_mbcs == 0)
1343 D_mbcs = c;
1344 D_x++;
1345 return;
1347 D_x--;
1348 if (D_x == D_width - 1)
1349 D_x += D_AM ? 1 : -1;
1350 c = D_mbcs;
1351 D_mbcs = t;
1353 # endif
1354 # if defined(ENCODINGS) && defined(DW_CHARS)
1355 if (D_encoding)
1356 c = PrepareEncodedChar(c);
1357 # endif
1358 # ifdef DW_CHARS
1359 kanjiloop:
1360 # endif
1361 if (D_xtable && D_xtable[(int)(unsigned char)D_rend.font] && D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c])
1362 AddStr(D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c]);
1363 else
1364 AddChar(D_rend.font != '0' ? c : D_c0_tab[(int)(unsigned char)c]);
1365 #else /* FONT */
1366 AddChar(c);
1367 #endif /* FONT */
1369 #ifdef UTF8
1370 addedutf8:
1371 #endif
1372 if (++D_x >= D_width)
1374 if (D_AM == 0)
1375 D_x = D_width - 1;
1376 else if (!D_CLP || D_x > D_width)
1378 D_x -= D_width;
1379 if (D_y < D_height-1 && D_y != D_bot)
1380 D_y++;
1383 #ifdef DW_CHARS
1384 if (D_mbcs)
1386 c = D_mbcs;
1387 D_mbcs = 0;
1388 goto kanjiloop;
1390 #endif
1393 static int
1394 DoAddChar(c)
1395 int c;
1397 /* this is for ESC-sequences only (AddChar is a macro) */
1398 AddChar(c);
1399 return c;
1402 void
1403 AddCStr(s)
1404 char *s;
1406 if (display && s && *s)
1408 ospeed = D_dospeed;
1409 tputs(s, 1, DoAddChar);
1413 void
1414 AddCStr2(s, c)
1415 char *s;
1416 int c;
1418 if (display && s && *s)
1420 ospeed = D_dospeed;
1421 tputs(tgoto(s, 0, c), 1, DoAddChar);
1426 /* Insert mode is a toggle on some terminals, so we need this hack:
1428 void
1429 InsertMode(on)
1430 int on;
1432 if (display && on != D_insert && D_IM)
1434 D_insert = on;
1435 if (on)
1436 AddCStr(D_IM);
1437 else
1438 AddCStr(D_EI);
1442 /* ...and maybe keypad application mode is a toggle, too:
1444 void
1445 KeypadMode(on)
1446 int on;
1448 #ifdef MAPKEYS
1449 if (display)
1450 D_keypad = on;
1451 #else
1452 if (display && D_keypad != on && D_KS)
1454 D_keypad = on;
1455 if (on)
1456 AddCStr(D_KS);
1457 else
1458 AddCStr(D_KE);
1460 #endif
1463 void
1464 CursorkeysMode(on)
1465 int on;
1467 #ifdef MAPKEYS
1468 if (display)
1469 D_cursorkeys = on;
1470 #else
1471 if (display && D_cursorkeys != on && D_CCS)
1473 D_cursorkeys = on;
1474 if (on)
1475 AddCStr(D_CCS);
1476 else
1477 AddCStr(D_CCE);
1479 #endif
1482 void
1483 ReverseVideo(on)
1484 int on;
1486 if (display && D_revvid != on && D_CVR)
1488 D_revvid = on;
1489 if (D_revvid)
1490 AddCStr(D_CVR);
1491 else
1492 AddCStr(D_CVN);
1496 void
1497 CursorVisibility(v)
1498 int v;
1500 if (display && D_curvis != v)
1502 if (D_curvis)
1503 AddCStr(D_VE); /* do this always, just to be safe */
1504 D_curvis = 0;
1505 if (v == -1 && D_VI)
1506 AddCStr(D_VI);
1507 else if (v == 1 && D_VS)
1508 AddCStr(D_VS);
1509 else
1510 return;
1511 D_curvis = v;
1515 void
1516 MouseMode(mode)
1517 int mode;
1519 if (display && D_mouse != mode)
1521 char mousebuf[20];
1522 if (!D_CXT)
1523 return;
1524 if (D_mouse)
1526 sprintf(mousebuf, "\033[?%dl", D_mouse);
1527 AddStr(mousebuf);
1529 if (mode)
1531 sprintf(mousebuf, "\033[?%dh", mode);
1532 AddStr(mousebuf);
1534 D_mouse = mode;
1538 static int StrCost;
1540 /* ARGSUSED */
1541 static int
1542 CountChars(c)
1543 int c;
1545 StrCost++;
1546 return c;
1550 CalcCost(s)
1551 register char *s;
1553 ASSERT(display);
1554 if (s)
1556 StrCost = 0;
1557 ospeed = D_dospeed;
1558 tputs(s, 1, CountChars);
1559 return StrCost;
1561 else
1562 return EXPENSIVE;
1565 static int
1566 CallRewrite(y, xs, xe, doit)
1567 int y, xs, xe, doit;
1569 struct canvas *cv, *cvlist, *cvlnext;
1570 struct viewport *vp;
1571 struct layer *oldflayer;
1572 int cost;
1574 debug3("CallRewrite %d %d %d\n", y, xs, xe);
1575 ASSERT(display);
1576 ASSERT(xe >= xs);
1578 vp = 0;
1579 for (cv = D_cvlist; cv; cv = cv->c_next)
1581 if (y < cv->c_ys || y > cv->c_ye || xe < cv->c_xs || xs > cv->c_xe)
1582 continue;
1583 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1584 if (y >= vp->v_ys && y <= vp->v_ye && xe >= vp->v_xs && xs <= vp->v_xe)
1585 break;
1586 if (vp)
1587 break;
1589 if (doit)
1591 oldflayer = flayer;
1592 flayer = cv->c_layer;
1593 cvlist = flayer->l_cvlist;
1594 cvlnext = cv->c_lnext;
1595 flayer->l_cvlist = cv;
1596 cv->c_lnext = 0;
1597 LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 1);
1598 flayer->l_cvlist = cvlist;
1599 cv->c_lnext = cvlnext;
1600 flayer = oldflayer;
1601 return 0;
1603 if (cv == 0 || cv->c_layer == 0)
1604 return EXPENSIVE; /* not found or nothing on it */
1605 if (xs < vp->v_xs || xe > vp->v_xe)
1606 return EXPENSIVE; /* crosses viewport boundaries */
1607 if (y - vp->v_yoff < 0 || y - vp->v_yoff >= cv->c_layer->l_height)
1608 return EXPENSIVE; /* line not on layer */
1609 if (xs - vp->v_xoff < 0 || xe - vp->v_xoff >= cv->c_layer->l_width)
1610 return EXPENSIVE; /* line not on layer */
1611 #ifdef UTF8
1612 if (D_encoding == UTF8)
1613 D_rend.font = 0;
1614 #endif
1615 oldflayer = flayer;
1616 flayer = cv->c_layer;
1617 debug3("Calling Rewrite %d %d %d\n", y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff);
1618 cost = LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 0);
1619 flayer = oldflayer;
1620 if (D_insert)
1621 cost += D_EIcost + D_IMcost;
1622 return cost;
1626 void
1627 GotoPos(x2, y2)
1628 int x2, y2;
1630 register int dy, dx, x1, y1;
1631 register int costx, costy;
1632 register int m;
1633 register char *s;
1634 int CMcost;
1635 enum move_t xm = M_NONE, ym = M_NONE;
1637 if (!display)
1638 return;
1640 x1 = D_x;
1641 y1 = D_y;
1643 if (x1 == D_width)
1645 if (D_CLP && D_AM)
1646 x1 = -1; /* don't know how the terminal treats this */
1647 else
1648 x1--;
1650 if (x2 == D_width)
1651 x2--;
1652 dx = x2 - x1;
1653 dy = y2 - y1;
1654 if (dy == 0 && dx == 0)
1655 return;
1656 debug2("GotoPos (%d,%d)", x1, y1);
1657 debug2(" -> (%d,%d)\n", x2, y2);
1658 if (!D_MS) /* Safe to move ? */
1659 SetRendition(&mchar_null);
1660 if (y1 < 0 /* don't know the y position */
1661 || (y2 > D_bot && y1 <= D_bot) /* have to cross border */
1662 || (y2 < D_top && y1 >= D_top)) /* of scrollregion ? */
1664 DoCM:
1665 if (D_HO && !x2 && !y2)
1666 AddCStr(D_HO);
1667 else
1668 AddCStr(tgoto(D_CM, x2, y2));
1669 D_x = x2;
1670 D_y = y2;
1671 return;
1674 /* some scrollregion implementations don't allow movements
1675 * away from the region. sigh.
1677 if ((y1 > D_bot && y2 > y1) || (y1 < D_top && y2 < y1))
1678 goto DoCM;
1680 /* Calculate CMcost */
1681 if (D_HO && !x2 && !y2)
1682 s = D_HO;
1683 else
1684 s = tgoto(D_CM, x2, y2);
1685 CMcost = CalcCost(s);
1687 /* Calculate the cost to move the cursor to the right x position */
1688 costx = EXPENSIVE;
1689 if (x1 >= 0) /* relativ x positioning only if we know where we are */
1691 if (dx > 0)
1693 if (D_CRI && (dx > 1 || !D_ND))
1695 costx = CalcCost(tgoto(D_CRI, 0, dx));
1696 xm = M_CRI;
1698 if ((m = D_NDcost * dx) < costx)
1700 costx = m;
1701 xm = M_RI;
1703 /* Speedup: dx <= LayRewrite() */
1704 if (dx < costx && (m = CallRewrite(y1, x1, x2 - 1, 0)) < costx)
1706 costx = m;
1707 xm = M_RW;
1710 else if (dx < 0)
1712 if (D_CLE && (dx < -1 || !D_BC))
1714 costx = CalcCost(tgoto(D_CLE, 0, -dx));
1715 xm = M_CLE;
1717 if ((m = -dx * D_LEcost) < costx)
1719 costx = m;
1720 xm = M_LE;
1723 else
1724 costx = 0;
1726 /* Speedup: LayRewrite() >= x2 */
1727 if (x2 + D_CRcost < costx && (m = (x2 ? CallRewrite(y1, 0, x2 - 1, 0) : 0) + D_CRcost) < costx)
1729 costx = m;
1730 xm = M_CR;
1733 /* Check if it is already cheaper to do CM */
1734 if (costx >= CMcost)
1735 goto DoCM;
1737 /* Calculate the cost to move the cursor to the right y position */
1738 costy = EXPENSIVE;
1739 if (dy > 0)
1741 if (D_CDO && dy > 1) /* DO & NL are always != 0 */
1743 costy = CalcCost(tgoto(D_CDO, 0, dy));
1744 ym = M_CDO;
1746 if ((m = dy * ((x2 == 0) ? D_NLcost : D_DOcost)) < costy)
1748 costy = m;
1749 ym = M_DO;
1752 else if (dy < 0)
1754 if (D_CUP && (dy < -1 || !D_UP))
1756 costy = CalcCost(tgoto(D_CUP, 0, -dy));
1757 ym = M_CUP;
1759 if ((m = -dy * D_UPcost) < costy)
1761 costy = m;
1762 ym = M_UP;
1765 else
1766 costy = 0;
1768 /* Finally check if it is cheaper to do CM */
1769 if (costx + costy >= CMcost)
1770 goto DoCM;
1772 switch (xm)
1774 case M_LE:
1775 while (dx++ < 0)
1776 AddCStr(D_BC);
1777 break;
1778 case M_CLE:
1779 AddCStr2(D_CLE, -dx);
1780 break;
1781 case M_RI:
1782 while (dx-- > 0)
1783 AddCStr(D_ND);
1784 break;
1785 case M_CRI:
1786 AddCStr2(D_CRI, dx);
1787 break;
1788 case M_CR:
1789 AddCStr(D_CR);
1790 D_x = 0;
1791 x1 = 0;
1792 /* FALLTHROUGH */
1793 case M_RW:
1794 if (x1 < x2)
1795 (void) CallRewrite(y1, x1, x2 - 1, 1);
1796 break;
1797 default:
1798 break;
1801 switch (ym)
1803 case M_UP:
1804 while (dy++ < 0)
1805 AddCStr(D_UP);
1806 break;
1807 case M_CUP:
1808 AddCStr2(D_CUP, -dy);
1809 break;
1810 case M_DO:
1811 s = (x2 == 0) ? D_NL : D_DO;
1812 while (dy-- > 0)
1813 AddCStr(s);
1814 break;
1815 case M_CDO:
1816 AddCStr2(D_CDO, dy);
1817 break;
1818 default:
1819 break;
1821 D_x = x2;
1822 D_y = y2;
1825 void
1826 ClearAll()
1828 ASSERT(display);
1829 ClearArea(0, 0, 0, D_width - 1, D_width - 1, D_height - 1, 0, 0);
1832 void
1833 ClearArea(x1, y1, xs, xe, x2, y2, bce, uselayfn)
1834 int x1, y1, xs, xe, x2, y2, bce, uselayfn;
1836 int y, xxe;
1837 struct canvas *cv;
1838 struct viewport *vp;
1840 debug2("Clear %d,%d", x1, y1);
1841 debug2(" %d-%d", xs, xe);
1842 debug2(" %d,%d", x2, y2);
1843 debug2(" uselayfn=%d bce=%d\n", uselayfn, bce);
1844 ASSERT(display);
1845 if (x1 == D_width)
1846 x1--;
1847 if (x2 == D_width)
1848 x2--;
1849 if (xs == -1)
1850 xs = x1;
1851 if (xe == -1)
1852 xe = x2;
1853 if (D_UT) /* Safe to erase ? */
1854 SetRendition(&mchar_null);
1855 #ifdef COLOR
1856 if (D_BE)
1857 SetBackColor(bce);
1858 #endif
1859 if (D_lp_missing && y1 <= D_bot && xe >= D_width - 1)
1861 if (y2 > D_bot || (y2 == D_bot && x2 >= D_width - 1))
1862 D_lp_missing = 0;
1864 if (x2 == D_width - 1 && (xs == 0 || y1 == y2) && xe == D_width - 1 && y2 == D_height - 1 && (!bce || D_BE))
1866 #ifdef AUTO_NUKE
1867 if (x1 == 0 && y1 == 0 && D_auto_nuke)
1868 NukePending();
1869 #endif
1870 if (x1 == 0 && y1 == 0 && D_CL)
1872 AddCStr(D_CL);
1873 D_y = D_x = 0;
1874 return;
1877 * Workaround a hp700/22 terminal bug. Do not use CD where CE
1878 * is also appropriate.
1880 if (D_CD && (y1 < y2 || !D_CE))
1882 GotoPos(x1, y1);
1883 AddCStr(D_CD);
1884 return;
1887 if (x1 == 0 && xs == 0 && (xe == D_width - 1 || y1 == y2) && y1 == 0 && D_CCD && (!bce || D_BE))
1889 GotoPos(x1, y1);
1890 AddCStr(D_CCD);
1891 return;
1893 xxe = xe;
1894 for (y = y1; y <= y2; y++, x1 = xs)
1896 if (y == y2)
1897 xxe = x2;
1898 if (x1 == 0 && D_CB && (xxe != D_width - 1 || (D_x == xxe && D_y == y)) && (!bce || D_BE))
1900 GotoPos(xxe, y);
1901 AddCStr(D_CB);
1902 continue;
1904 if (xxe == D_width - 1 && D_CE && (!bce || D_BE))
1906 GotoPos(x1, y);
1907 AddCStr(D_CE);
1908 continue;
1910 if (uselayfn)
1912 vp = 0;
1913 for (cv = D_cvlist; cv; cv = cv->c_next)
1915 if (y < cv->c_ys || y > cv->c_ye || xxe < cv->c_xs || x1 > cv->c_xe)
1916 continue;
1917 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1918 if (y >= vp->v_ys && y <= vp->v_ye && xxe >= vp->v_xs && x1 <= vp->v_xe)
1919 break;
1920 if (vp)
1921 break;
1923 if (cv && cv->c_layer && x1 >= vp->v_xs && xxe <= vp->v_xe &&
1924 y - vp->v_yoff >= 0 && y - vp->v_yoff < cv->c_layer->l_height &&
1925 xxe - vp->v_xoff >= 0 && x1 - vp->v_xoff < cv->c_layer->l_width)
1927 struct layer *oldflayer = flayer;
1928 struct canvas *cvlist, *cvlnext;
1929 flayer = cv->c_layer;
1930 cvlist = flayer->l_cvlist;
1931 cvlnext = cv->c_lnext;
1932 flayer->l_cvlist = cv;
1933 cv->c_lnext = 0;
1934 LayClearLine(y - vp->v_yoff, x1 - vp->v_xoff, xxe - vp->v_xoff, bce);
1935 flayer->l_cvlist = cvlist;
1936 cv->c_lnext = cvlnext;
1937 flayer = oldflayer;
1938 continue;
1941 ClearLine((struct mline *)0, y, x1, xxe, bce);
1947 * if cur_only > 0, we only redisplay current line, as a full refresh is
1948 * too expensive over a low baud line.
1950 void
1951 Redisplay(cur_only)
1952 int cur_only;
1954 ASSERT(display);
1956 /* XXX do em all? */
1957 InsertMode(0);
1958 ChangeScrollRegion(0, D_height - 1);
1959 KeypadMode(0);
1960 CursorkeysMode(0);
1961 CursorVisibility(0);
1962 MouseMode(0);
1963 SetRendition(&mchar_null);
1964 SetFlow(FLOW_NOW);
1966 ClearAll();
1967 #ifdef RXVT_OSC
1968 RefreshXtermOSC();
1969 #endif
1970 if (cur_only > 0 && D_fore)
1971 RefreshArea(0, D_fore->w_y, D_width - 1, D_fore->w_y, 1);
1972 else
1973 RefreshAll(1);
1974 RefreshHStatus();
1975 CV_CALL(D_forecv, LayRestore();LaySetCursor());
1978 void
1979 RedisplayDisplays(cur_only)
1980 int cur_only;
1982 struct display *olddisplay = display;
1983 for (display = displays; display; display = display->d_next)
1984 Redisplay(cur_only);
1985 display = olddisplay;
1989 /* XXX: use oml! */
1990 void
1991 ScrollH(y, xs, xe, n, bce, oml)
1992 int y, xs, xe, n, bce;
1993 struct mline *oml;
1995 int i;
1997 if (n == 0)
1998 return;
1999 if (xe != D_width - 1)
2001 RefreshLine(y, xs, xe, 0);
2002 /* UpdateLine(oml, y, xs, xe); */
2003 return;
2005 GotoPos(xs, y);
2006 if (D_UT)
2007 SetRendition(&mchar_null);
2008 #ifdef COLOR
2009 if (D_BE)
2010 SetBackColor(bce);
2011 #endif
2012 if (n > 0)
2014 if (n >= xe - xs + 1)
2015 n = xe - xs + 1;
2016 if (D_CDC && !(n == 1 && D_DC))
2017 AddCStr2(D_CDC, n);
2018 else if (D_DC)
2020 for (i = n; i--; )
2021 AddCStr(D_DC);
2023 else
2025 RefreshLine(y, xs, xe, 0);
2026 /* UpdateLine(oml, y, xs, xe); */
2027 return;
2030 else
2032 if (-n >= xe - xs + 1)
2033 n = -(xe - xs + 1);
2034 if (!D_insert)
2036 if (D_CIC && !(n == -1 && D_IC))
2037 AddCStr2(D_CIC, -n);
2038 else if (D_IC)
2040 for (i = -n; i--; )
2041 AddCStr(D_IC);
2043 else if (D_IM)
2045 InsertMode(1);
2046 SetRendition(&mchar_null);
2047 #ifdef COLOR
2048 SetBackColor(bce);
2049 #endif
2050 for (i = -n; i--; )
2051 INSERTCHAR(' ');
2052 bce = 0; /* all done */
2054 else
2056 /* UpdateLine(oml, y, xs, xe); */
2057 RefreshLine(y, xs, xe, 0);
2058 return;
2061 else
2063 SetRendition(&mchar_null);
2064 #ifdef COLOR
2065 SetBackColor(bce);
2066 #endif
2067 for (i = -n; i--; )
2068 INSERTCHAR(' ');
2069 bce = 0; /* all done */
2072 if (bce && !D_BE)
2074 if (n > 0)
2075 ClearLine((struct mline *)0, y, xe - n + 1, xe, bce);
2076 else
2077 ClearLine((struct mline *)0, y, xs, xs - n - 1, bce);
2079 if (D_lp_missing && y == D_bot)
2081 if (n > 0)
2082 WriteLP(D_width - 1 - n, y);
2083 D_lp_missing = 0;
2087 void
2088 ScrollV(xs, ys, xe, ye, n, bce)
2089 int xs, ys, xe, ye, n, bce;
2091 int i;
2092 int up;
2093 int oldtop, oldbot;
2094 int alok, dlok, aldlfaster;
2095 int missy = 0;
2097 ASSERT(display);
2098 if (n == 0)
2099 return;
2100 if (n >= ye - ys + 1 || -n >= ye - ys + 1)
2102 ClearArea(xs, ys, xs, xe, xe, ye, bce, 0);
2103 return;
2105 if (xs > D_vpxmin || xe < D_vpxmax)
2107 RefreshArea(xs, ys, xe, ye, 0);
2108 return;
2111 if (D_lp_missing)
2113 if (D_bot > ye || D_bot < ys)
2114 missy = D_bot;
2115 else
2117 missy = D_bot - n;
2118 if (missy > ye || missy < ys)
2119 D_lp_missing = 0;
2123 up = 1;
2124 if (n < 0)
2126 up = 0;
2127 n = -n;
2129 if (n >= ye - ys + 1)
2130 n = ye - ys + 1;
2132 oldtop = D_top;
2133 oldbot = D_bot;
2134 if (ys < D_top || D_bot != ye)
2135 ChangeScrollRegion(ys, ye);
2136 alok = (D_AL || D_CAL || (ys >= D_top && ye == D_bot && up));
2137 dlok = (D_DL || D_CDL || (ys >= D_top && ye == D_bot && !up));
2138 if (D_top != ys && !(alok && dlok))
2139 ChangeScrollRegion(ys, ye);
2141 if (D_lp_missing &&
2142 (oldbot != D_bot ||
2143 (oldbot == D_bot && up && D_top == ys && D_bot == ye)))
2145 WriteLP(D_width - 1, oldbot);
2146 if (oldbot == D_bot) /* have scrolled */
2148 if (--n == 0)
2150 /* XXX
2151 ChangeScrollRegion(oldtop, oldbot);
2153 if (bce && !D_BE)
2154 ClearLine((struct mline *)0, ye, xs, xe, bce);
2155 return;
2160 if (D_UT)
2161 SetRendition(&mchar_null);
2162 #ifdef COLOR
2163 if (D_BE)
2164 SetBackColor(bce);
2165 #endif
2167 aldlfaster = (n > 1 && ys >= D_top && ye == D_bot && ((up && D_CDL) || (!up && D_CAL)));
2169 if ((up || D_SR) && D_top == ys && D_bot == ye && !aldlfaster)
2171 if (up)
2173 GotoPos(0, ye);
2174 for(i = n; i-- > 0; )
2175 AddCStr(D_NL); /* was SF, I think NL is faster */
2177 else
2179 GotoPos(0, ys);
2180 for(i = n; i-- > 0; )
2181 AddCStr(D_SR);
2184 else if (alok && dlok)
2186 if (up || ye != D_bot)
2188 GotoPos(0, up ? ys : ye+1-n);
2189 if (D_CDL && !(n == 1 && D_DL))
2190 AddCStr2(D_CDL, n);
2191 else
2192 for(i = n; i--; )
2193 AddCStr(D_DL);
2195 if (!up || ye != D_bot)
2197 GotoPos(0, up ? ye+1-n : ys);
2198 if (D_CAL && !(n == 1 && D_AL))
2199 AddCStr2(D_CAL, n);
2200 else
2201 for(i = n; i--; )
2202 AddCStr(D_AL);
2205 else
2207 RefreshArea(xs, ys, xe, ye, 0);
2208 return;
2210 if (bce && !D_BE)
2212 if (up)
2213 ClearArea(xs, ye - n + 1, xs, xe, xe, ye, bce, 0);
2214 else
2215 ClearArea(xs, ys, xs, xe, xe, ys + n - 1, bce, 0);
2217 if (D_lp_missing && missy != D_bot)
2218 WriteLP(D_width - 1, missy);
2219 /* XXX
2220 ChangeScrollRegion(oldtop, oldbot);
2221 if (D_lp_missing && missy != D_bot)
2222 WriteLP(D_width - 1, missy);
2226 void
2227 SetAttr(new)
2228 register int new;
2230 register int i, j, old, typ;
2232 if (!display || (old = D_rend.attr) == new)
2233 return;
2234 #ifdef COLORS16
2235 D_col16change = (old ^ new) & (A_BFG | A_BBG);
2236 new ^= D_col16change;
2237 if (old == new)
2238 return;
2239 #endif
2240 #if defined(TERMINFO) && defined(USE_SGR)
2241 if (D_SA)
2243 char *tparm();
2244 SetFont(ASCII);
2245 ospeed = D_dospeed;
2246 tputs(tparm(D_SA, new & A_SO, new & A_US, new & A_RV, new & A_BL,
2247 new & A_DI, new & A_BD, 0 , 0 ,
2248 0), 1, DoAddChar);
2249 D_rend.attr = new;
2250 D_atyp = 0;
2251 # ifdef COLOR
2252 if (D_hascolor)
2253 rend_setdefault(&D_rend);
2254 # endif
2255 return;
2257 #endif
2258 D_rend.attr = new;
2259 typ = D_atyp;
2260 if ((new & old) != old)
2262 if ((typ & ATYP_U))
2263 AddCStr(D_UE);
2264 if ((typ & ATYP_S))
2265 AddCStr(D_SE);
2266 if ((typ & ATYP_M))
2268 AddCStr(D_ME);
2269 #ifdef COLOR
2270 /* ansi attrib handling: \E[m resets color, too */
2271 if (D_hascolor)
2272 rend_setdefault(&D_rend);
2273 #endif
2274 #ifdef FONT
2275 if (!D_CG0)
2277 /* D_ME may also reset the alternate charset */
2278 D_rend.font = 0;
2279 # ifdef ENCODINGS
2280 D_realfont = 0;
2281 # endif
2283 #endif
2285 old = 0;
2286 typ = 0;
2288 old ^= new;
2289 for (i = 0, j = 1; old && i < NATTR; i++, j <<= 1)
2291 if ((old & j) == 0)
2292 continue;
2293 old ^= j;
2294 if (D_attrtab[i])
2296 AddCStr(D_attrtab[i]);
2297 typ |= D_attrtyp[i];
2300 D_atyp = typ;
2303 #ifdef FONT
2304 void
2305 SetFont(new)
2306 int new;
2308 int old = D_rend.font;
2309 if (!display || old == new)
2310 return;
2311 D_rend.font = new;
2312 #ifdef ENCODINGS
2313 if (D_encoding && CanEncodeFont(D_encoding, new))
2314 return;
2315 if (new == D_realfont)
2316 return;
2317 D_realfont = new;
2318 #endif
2319 if (D_xtable && D_xtable[(int)(unsigned char)new] &&
2320 D_xtable[(int)(unsigned char)new][256])
2322 AddCStr(D_xtable[(int)(unsigned char)new][256]);
2323 return;
2326 if (!D_CG0 && new != '0')
2328 new = ASCII;
2329 if (old == new)
2330 return;
2333 if (new == ASCII)
2334 AddCStr(D_CE0);
2335 #ifdef DW_CHARS
2336 else if (new < ' ')
2338 AddStr("\033$");
2339 if (new > 2)
2340 AddChar('(');
2341 AddChar(new + '@');
2343 #endif
2344 else
2345 AddCStr2(D_CS0, new);
2347 #endif
2349 #ifdef COLOR
2352 color256to16(jj)
2353 int jj;
2355 int min, max;
2356 int r, g, b;
2358 if (jj >= 232)
2360 jj = (jj - 232) / 6;
2361 jj = (jj & 1) << 3 | (jj & 2 ? 7 : 0);
2363 else if (jj >= 16)
2365 jj -= 16;
2366 r = jj / 36;
2367 g = (jj / 6) % 6;
2368 b = jj % 6;
2369 min = r < g ? (r < b ? r : b) : (g < b ? g : b);
2370 max = r > g ? (r > b ? r : b) : (g > b ? g : b);
2371 if (min == max)
2372 jj = ((max + 1) & 2) << 2 | ((max + 1) & 4 ? 7 : 0);
2373 else
2374 jj = (b - min) / (max - min) << 2 | (g - min) / (max - min) << 1 | (r -
2375 min) / (max - min) | (max > 3 ? 8 : 0);
2377 return jj;
2380 #ifdef COLORS256
2382 color256to88(jj)
2383 int jj;
2385 int r, g, b;
2387 if (jj >= 232)
2388 return (jj - 232) / 3 + 80;
2389 if (jj >= 16)
2391 jj -= 16;
2392 r = jj / 36;
2393 g = (jj / 6) % 6;
2394 b = jj % 6;
2395 return ((r + 1) / 2) * 16 + ((g + 1) / 2) * 4 + ((b + 1) / 2) + 16;
2397 return jj;
2399 #endif
2401 void
2402 SetColor(f, b)
2403 int f, b;
2405 int of, ob;
2406 static unsigned char sftrans[8] = {0,4,2,6,1,5,3,7};
2408 if (!display)
2409 return;
2411 of = rend_getfg(&D_rend);
2412 ob = rend_getbg(&D_rend);
2414 #ifdef COLORS16
2415 /* intense default not invented yet */
2416 if (f == 0x100)
2417 f = 0;
2418 if (b == 0x100)
2419 b = 0;
2420 #endif
2421 debug2("SetColor %d %d", coli2e(of), coli2e(ob));
2422 debug2(" -> %d %d\n", coli2e(f), coli2e(b));
2423 debug2("(%d %d", of, ob);
2424 debug2(" -> %d %d)\n", f, b);
2426 if (!D_CAX && D_hascolor && ((f == 0 && f != of) || (b == 0 && b != ob)))
2428 if (D_OP)
2429 AddCStr(D_OP);
2430 else
2432 int oattr;
2433 oattr = D_rend.attr;
2434 AddCStr(D_ME ? D_ME : "\033[m");
2435 #ifdef FONT
2436 if (D_ME && !D_CG0)
2438 /* D_ME may also reset the alternate charset */
2439 D_rend.font = 0;
2440 # ifdef ENCODINGS
2441 D_realfont = 0;
2442 # endif
2444 #endif
2445 D_atyp = 0;
2446 D_rend.attr = 0;
2447 SetAttr(oattr);
2449 of = ob = 0;
2451 rend_setfg(&D_rend, f);
2452 rend_setbg(&D_rend, b);
2453 #ifdef COLORS16
2454 D_col16change = 0;
2455 #endif
2456 if (!D_hascolor)
2457 return;
2458 f = f ? coli2e(f) : -1;
2459 b = b ? coli2e(b) : -1;
2460 of = of ? coli2e(of) : -1;
2461 ob = ob ? coli2e(ob) : -1;
2462 #ifdef COLORS256
2463 if (f != of && f > 15 && D_CCO != 256)
2464 f = D_CCO == 88 && D_CAF ? color256to88(f) : color256to16(f);
2465 if (f != of && f > 15 && D_CAF)
2467 AddCStr2(D_CAF, f);
2468 of = f;
2470 if (b != ob && b > 15 && D_CCO != 256)
2471 b = D_CCO == 88 && D_CAB ? color256to88(b) : color256to16(b);
2472 if (b != ob && b > 15 && D_CAB)
2474 AddCStr2(D_CAB, b);
2475 ob = b;
2477 #endif
2478 if (f != of && f != (of | 8))
2480 if (f == -1)
2481 AddCStr("\033[39m"); /* works because AX is set */
2482 else if (D_CAF)
2483 AddCStr2(D_CAF, f & 7);
2484 else if (D_CSF)
2485 AddCStr2(D_CSF, sftrans[f & 7]);
2487 if (b != ob && b != (ob | 8))
2489 if (b == -1)
2490 AddCStr("\033[49m"); /* works because AX is set */
2491 else if (D_CAB)
2492 AddCStr2(D_CAB, b & 7);
2493 else if (D_CSB)
2494 AddCStr2(D_CSB, sftrans[b & 7]);
2496 #ifdef COLORS16
2497 if (f != of && D_CXT && (f & 8) != 0 && f != -1)
2499 # ifdef TERMINFO
2500 AddCStr2("\033[9%p1%dm", f & 7);
2501 # else
2502 AddCStr2("\033[9%dm", f & 7);
2503 # endif
2505 if (b != ob && D_CXT && (b & 8) != 0 && b != -1)
2507 # ifdef TERMINFO
2508 AddCStr2("\033[10%p1%dm", b & 7);
2509 # else
2510 AddCStr2("\033[10%dm", b & 7);
2511 # endif
2513 #endif
2516 static void
2517 SetBackColor(new)
2518 int new;
2520 if (!display)
2521 return;
2522 SetColor(rend_getfg(&D_rend), new);
2524 #endif /* COLOR */
2526 void
2527 SetRendition(mc)
2528 struct mchar *mc;
2530 if (!display)
2531 return;
2532 if (nattr2color && D_hascolor && (mc->attr & nattr2color) != 0)
2534 static struct mchar mmc;
2535 int i;
2536 mmc = *mc;
2537 for (i = 0; i < 8; i++)
2538 if (attr2color[i] && (mc->attr & (1 << i)) != 0)
2540 if (mc->color == 0 && attr2color[i][3])
2541 ApplyAttrColor(attr2color[i][3], &mmc);
2542 else if ((mc->color & 0x0f) == 0 && attr2color[i][2])
2543 ApplyAttrColor(attr2color[i][2], &mmc);
2544 else if ((mc->color & 0xf0) == 0 && attr2color[i][1])
2545 ApplyAttrColor(attr2color[i][1], &mmc);
2546 else
2547 ApplyAttrColor(attr2color[i][0], &mmc);
2549 mc = &mmc;
2550 debug2("SetRendition: mapped to %02x %02x\n", (unsigned char)mc->attr, 0x99 - (unsigned char)mc->color);
2552 if (D_hascolor && D_CC8 && (mc->attr & (A_BFG|A_BBG)))
2554 int a = mc->attr;
2555 if ((mc->attr & A_BFG) && D_MD)
2556 a |= A_BD;
2557 if ((mc->attr & A_BBG) && D_MB)
2558 a |= A_BL;
2559 if (D_rend.attr != a)
2560 SetAttr(a);
2562 else if (D_rend.attr != mc->attr)
2563 SetAttr(mc->attr);
2564 #ifdef COLOR
2565 if (D_rend.color != mc->color
2566 # ifdef COLORS256
2567 || D_rend.colorx != mc->colorx
2568 # endif
2569 # ifdef COLORS16
2570 || D_col16change
2571 # endif
2573 SetColor(rend_getfg(mc), rend_getbg(mc));
2574 #endif
2575 #ifdef FONT
2576 if (D_rend.font != mc->font)
2577 SetFont(mc->font);
2578 #endif
2581 void
2582 SetRenditionMline(ml, x)
2583 struct mline *ml;
2584 int x;
2586 if (!display)
2587 return;
2588 if (nattr2color && D_hascolor && (ml->attr[x] & nattr2color) != 0)
2590 struct mchar mc;
2591 copy_mline2mchar(&mc, ml, x);
2592 SetRendition(&mc);
2593 return;
2595 if (D_hascolor && D_CC8 && (ml->attr[x] & (A_BFG|A_BBG)))
2597 int a = ml->attr[x];
2598 if ((ml->attr[x] & A_BFG) && D_MD)
2599 a |= A_BD;
2600 if ((ml->attr[x] & A_BBG) && D_MB)
2601 a |= A_BL;
2602 if (D_rend.attr != a)
2603 SetAttr(a);
2605 else if (D_rend.attr != ml->attr[x])
2606 SetAttr(ml->attr[x]);
2607 #ifdef COLOR
2608 if (D_rend.color != ml->color[x]
2609 # ifdef COLORS256
2610 || D_rend.colorx != ml->colorx[x]
2611 # endif
2612 # ifdef COLORS16
2613 || D_col16change
2614 # endif
2617 struct mchar mc;
2618 copy_mline2mchar(&mc, ml, x);
2619 SetColor(rend_getfg(&mc), rend_getbg(&mc));
2621 #endif
2622 #ifdef FONT
2623 if (D_rend.font != ml->font[x])
2624 SetFont(ml->font[x]);
2625 #endif
2628 void
2629 MakeStatus(msg)
2630 char *msg;
2632 register char *s, *t;
2633 register int max;
2635 if (!display)
2636 return;
2638 if (D_blocked)
2639 return;
2640 if (!D_tcinited)
2642 debug("tc not inited, just writing msg\n");
2643 if (D_processinputdata)
2644 return; /* XXX: better */
2645 AddStr(msg);
2646 AddStr("\r\n");
2647 Flush();
2648 return;
2650 if (!use_hardstatus || !D_HS)
2652 max = D_width;
2653 if (D_CLP == 0)
2654 max--;
2656 else
2657 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2658 if (D_status)
2660 /* same message? */
2661 if (strcmp(msg, D_status_lastmsg) == 0)
2663 debug("same message - increase timeout");
2664 SetTimeout(&D_statusev, MsgWait);
2665 return;
2667 if (!D_status_bell)
2669 struct timeval now;
2670 int ti;
2671 gettimeofday(&now, NULL);
2672 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
2673 if (ti < MsgMinWait)
2674 DisplaySleep1000(MsgMinWait - ti, 0);
2676 RemoveStatus();
2678 for (s = t = msg; *s && t - msg < max; ++s)
2679 if (*s == BELL)
2680 AddCStr(D_BL);
2681 else if ((unsigned char)*s >= ' ' && *s != 0177)
2682 *t++ = *s;
2683 *t = '\0';
2684 if (t == msg)
2685 return;
2686 if (t - msg >= D_status_buflen)
2688 char *buf;
2689 if (D_status_lastmsg)
2690 buf = realloc(D_status_lastmsg, t - msg + 1);
2691 else
2692 buf = malloc(t - msg + 1);
2693 if (buf)
2695 D_status_lastmsg = buf;
2696 D_status_buflen = t - msg + 1;
2699 if (t - msg < D_status_buflen)
2700 strcpy(D_status_lastmsg, msg);
2701 D_status_len = t - msg;
2702 D_status_lastx = D_x;
2703 D_status_lasty = D_y;
2704 if (!use_hardstatus || D_has_hstatus == HSTATUS_IGNORE || D_has_hstatus == HSTATUS_MESSAGE)
2706 D_status = STATUS_ON_WIN;
2707 debug1("using STATLINE %d\n", STATLINE);
2708 GotoPos(0, STATLINE);
2709 SetRendition(&mchar_so);
2710 InsertMode(0);
2711 AddStr(msg);
2712 if (D_status_len < max)
2714 /* Wayne Davison: add extra space for readability */
2715 D_status_len++;
2716 SetRendition(&mchar_null);
2717 AddChar(' ');
2718 if (D_status_len < max)
2720 D_status_len++;
2721 AddChar(' ');
2722 AddChar('\b');
2724 AddChar('\b');
2726 D_x = -1;
2728 else
2730 D_status = STATUS_ON_HS;
2731 ShowHStatus(msg);
2733 Flush();
2734 if (!display)
2735 return;
2736 if (D_status == STATUS_ON_WIN)
2738 struct display *olddisplay = display;
2739 struct layer *oldflayer = flayer;
2741 ASSERT(D_obuffree == D_obuflen);
2742 /* this is copied over from RemoveStatus() */
2743 D_status = 0;
2744 GotoPos(0, STATLINE);
2745 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2746 GotoPos(D_status_lastx, D_status_lasty);
2747 flayer = D_forecv ? D_forecv->c_layer : 0;
2748 if (flayer)
2749 LaySetCursor();
2750 display = olddisplay;
2751 flayer = oldflayer;
2752 D_status_obuflen = D_obuflen;
2753 D_status_obuffree = D_obuffree;
2754 D_obuffree = D_obuflen = 0;
2755 D_status = STATUS_ON_WIN;
2757 gettimeofday(&D_status_time, NULL);
2758 SetTimeout(&D_statusev, MsgWait);
2759 evenq(&D_statusev);
2760 #ifdef HAVE_BRAILLE
2761 RefreshBraille(); /* let user see multiple Msg()s */
2762 #endif
2765 void
2766 RemoveStatus()
2768 struct display *olddisplay;
2769 struct layer *oldflayer;
2770 int where;
2772 if (!display)
2773 return;
2774 if (!(where = D_status))
2775 return;
2777 debug("RemoveStatus\n");
2778 if (D_status_obuffree >= 0)
2780 D_obuflen = D_status_obuflen;
2781 D_obuffree = D_status_obuffree;
2782 D_status_obuffree = -1;
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 if (captionalways || (D_canvas.c_slperp && D_canvas.c_slperp->c_slnext))
2793 GotoPos(0, STATLINE);
2794 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2795 GotoPos(D_status_lastx, D_status_lasty);
2798 else
2799 RefreshHStatus();
2800 flayer = D_forecv ? D_forecv->c_layer : 0;
2801 if (flayer)
2802 LaySetCursor();
2803 display = olddisplay;
2804 flayer = oldflayer;
2807 /* refresh the display's hstatus line */
2808 void
2809 ShowHStatus(str)
2810 char *str;
2812 int l, ox, oy, max;
2814 if (D_status == STATUS_ON_WIN && D_has_hstatus == HSTATUS_LASTLINE && STATLINE == D_height-1)
2815 return; /* sorry, in use */
2816 if (D_blocked)
2817 return;
2819 if (D_HS && D_has_hstatus == HSTATUS_HS)
2821 if (!D_hstatus && (str == 0 || *str == 0))
2822 return;
2823 debug("ShowHStatus: using HS\n");
2824 SetRendition(&mchar_null);
2825 InsertMode(0);
2826 if (D_hstatus)
2827 AddCStr(D_DS);
2828 D_hstatus = 0;
2829 if (str == 0 || *str == 0)
2830 return;
2831 AddCStr2(D_TS, 0);
2832 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2833 if ((int)strlen(str) > max)
2834 AddStrn(str, max);
2835 else
2836 AddStr(str);
2837 AddCStr(D_FS);
2838 D_hstatus = 1;
2840 else if (D_has_hstatus == HSTATUS_LASTLINE)
2842 debug("ShowHStatus: using last line\n");
2843 ox = D_x;
2844 oy = D_y;
2845 str = str ? str : "";
2846 l = strlen(str);
2847 if (l > D_width)
2848 l = D_width;
2849 GotoPos(0, D_height - 1);
2850 SetRendition(captionalways || D_cvlist == 0 || D_cvlist->c_next ? &mchar_null: &mchar_so);
2851 PutWinMsg(str, 0, l);
2852 if (!captionalways && D_cvlist && !D_cvlist->c_next)
2853 while (l++ < D_width)
2854 PUTCHARLP(' ');
2855 if (l < D_width)
2856 ClearArea(l, D_height - 1, l, D_width - 1, D_width - 1, D_height - 1, 0, 0);
2857 if (ox != -1 && oy != -1)
2858 GotoPos(ox, oy);
2859 D_hstatus = *str ? 1 : 0;
2860 SetRendition(&mchar_null);
2862 else if (str && *str && D_has_hstatus == HSTATUS_MESSAGE)
2864 debug("ShowHStatus: using message\n");
2865 Msg(0, "%s", str);
2871 * Refreshes the harstatus of the fore window. Shouldn't be here...
2873 void
2874 RefreshHStatus()
2876 char *buf;
2878 evdeq(&D_hstatusev);
2879 if (D_status == STATUS_ON_HS)
2880 return;
2881 buf = MakeWinMsgEv(hstatusstring, D_fore, '%', (D_HS && D_has_hstatus == HSTATUS_HS && D_WS > 0) ? D_WS : D_width - !D_CLP, &D_hstatusev, 0);
2882 if (buf && *buf)
2884 ShowHStatus(buf);
2885 if (D_has_hstatus != HSTATUS_IGNORE && D_hstatusev.timeout.tv_sec)
2886 evenq(&D_hstatusev);
2888 else
2889 ShowHStatus((char *)0);
2892 /*********************************************************************/
2894 * Here come the routines that refresh an arbitrary part of the screen.
2897 void
2898 RefreshAll(isblank)
2899 int isblank;
2901 struct canvas *cv;
2903 ASSERT(display);
2904 debug("Signalling full refresh!\n");
2905 for (cv = D_cvlist; cv; cv = cv->c_next)
2907 CV_CALL(cv, LayRedisplayLine(-1, -1, -1, isblank));
2908 display = cv->c_display; /* just in case! */
2910 RefreshArea(0, 0, D_width - 1, D_height - 1, isblank);
2913 void
2914 RefreshArea(xs, ys, xe, ye, isblank)
2915 int xs, ys, xe, ye, isblank;
2917 int y;
2918 ASSERT(display);
2919 debug2("Refresh Area: %d,%d", xs, ys);
2920 debug3(" - %d,%d (isblank=%d)\n", xe, ye, isblank);
2921 if (!isblank && xs == 0 && xe == D_width - 1 && ye == D_height - 1 && (ys == 0 || D_CD))
2923 ClearArea(xs, ys, xs, xe, xe, ye, 0, 0);
2924 isblank = 1;
2926 for (y = ys; y <= ye; y++)
2927 RefreshLine(y, xs, xe, isblank);
2930 void
2931 RefreshLine(y, from, to, isblank)
2932 int y, from, to, isblank;
2934 struct viewport *vp, *lvp;
2935 struct canvas *cv, *lcv, *cvlist, *cvlnext;
2936 struct layer *oldflayer;
2937 int xx, yy, l;
2938 char *buf;
2939 struct win *p;
2941 ASSERT(display);
2943 debug2("RefreshLine %d %d", y, from);
2944 debug2(" %d %d\n", to, isblank);
2946 if (D_status == STATUS_ON_WIN && y == STATLINE)
2948 if (to >= D_status_len)
2949 D_status_len = to + 1;
2950 return; /* can't refresh status */
2953 /* The following check makes plenty of sense. Unfortunately,
2954 vte-based terminals (notably gnome-terminal) experience a quirk
2955 that causes the final line not to update properly when it falls outside
2956 the scroll region; clearing the line with D_CE avoids the glitch,
2957 so we'll disable this perfectly sensible shortcut until such a time
2958 as widespread vte installations lack the glitch.
2960 See http://bugzilla.gnome.org/show_bug.cgi?id=542087 for current
2961 status of the VTE bug report, and
2962 https://savannah.gnu.org/bugs/index.php?23699 for the history from
2963 the Savannah BTS. */
2964 #if 0
2965 if (y == D_height - 1 && D_has_hstatus == HSTATUS_LASTLINE)
2967 RefreshHStatus();
2968 return;
2970 #endif
2972 if (isblank == 0 && D_CE && to == D_width - 1 && from < to)
2974 GotoPos(from, y);
2975 if (D_UT || D_BE)
2976 SetRendition(&mchar_null);
2977 AddCStr(D_CE);
2978 isblank = 1;
2980 while (from <= to)
2982 lcv = 0;
2983 lvp = 0;
2984 for (cv = display->d_cvlist; cv; cv = cv->c_next)
2986 if (y == cv->c_ye + 1 && from >= cv->c_xs && from <= cv->c_xe)
2988 p = Layer2Window(cv->c_layer);
2989 buf = MakeWinMsgEv(captionstring, p, '%', cv->c_xe - cv->c_xs + (cv->c_xe + 1 < D_width || D_CLP), &cv->c_captev, 0);
2990 if (cv->c_captev.timeout.tv_sec)
2991 evenq(&cv->c_captev);
2992 xx = to > cv->c_xe ? cv->c_xe : to;
2993 l = strlen(buf);
2994 GotoPos(from, y);
2995 SetRendition(&mchar_so);
2996 if (l > xx - cv->c_xs + 1)
2997 l = xx - cv->c_xs + 1;
2998 PutWinMsg(buf, from - cv->c_xs, l);
2999 from = cv->c_xs + l;
3000 for (; from <= xx; from++)
3001 PUTCHARLP(' ');
3002 break;
3004 if (from == cv->c_xe + 1 && y >= cv->c_ys && y <= cv->c_ye + 1)
3006 GotoPos(from, y);
3007 SetRendition(&mchar_so);
3008 PUTCHARLP(' ');
3009 from++;
3010 break;
3012 if (y < cv->c_ys || y > cv->c_ye || to < cv->c_xs || from > cv->c_xe)
3013 continue;
3014 debug2("- canvas hit: %d %d", cv->c_xs, cv->c_ys);
3015 debug2(" %d %d\n", cv->c_xe, cv->c_ye);
3016 for (vp = cv->c_vplist; vp; vp = vp->v_next)
3018 debug2(" - vp: %d %d", vp->v_xs, vp->v_ys);
3019 debug2(" %d %d\n", vp->v_xe, vp->v_ye);
3020 /* find leftmost overlapping vp */
3021 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))
3023 lcv = cv;
3024 lvp = vp;
3028 if (cv)
3029 continue; /* we advanced from */
3030 if (lvp == 0)
3031 break;
3032 if (from < lvp->v_xs)
3034 if (!isblank)
3035 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xs - 1);
3036 from = lvp->v_xs;
3039 /* call LayRedisplayLine on canvas lcv viewport lvp */
3040 yy = y - lvp->v_yoff;
3041 xx = to < lvp->v_xe ? to : lvp->v_xe;
3043 if (lcv->c_layer && yy == lcv->c_layer->l_height)
3045 GotoPos(from, y);
3046 SetRendition(&mchar_blank);
3047 while (from <= lvp->v_xe && from - lvp->v_xoff < lcv->c_layer->l_width)
3049 PUTCHARLP('-');
3050 from++;
3052 if (from >= lvp->v_xe + 1)
3053 continue;
3055 if (lcv->c_layer == 0 || yy >= lcv->c_layer->l_height || from - lvp->v_xoff >= lcv->c_layer->l_width)
3057 if (!isblank)
3058 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xe);
3059 from = lvp->v_xe + 1;
3060 continue;
3063 if (xx - lvp->v_xoff >= lcv->c_layer->l_width)
3064 xx = lcv->c_layer->l_width + lvp->v_xoff - 1;
3065 oldflayer = flayer;
3066 flayer = lcv->c_layer;
3067 cvlist = flayer->l_cvlist;
3068 cvlnext = lcv->c_lnext;
3069 flayer->l_cvlist = lcv;
3070 lcv->c_lnext = 0;
3071 LayRedisplayLine(yy, from - lvp->v_xoff, xx - lvp->v_xoff, isblank);
3072 flayer->l_cvlist = cvlist;
3073 lcv->c_lnext = cvlnext;
3074 flayer = oldflayer;
3076 from = xx + 1;
3078 if (!isblank && from <= to)
3079 DisplayLine(&mline_null, &mline_blank, y, from, to);
3082 /*********************************************************************/
3084 /* clear lp_missing by writing the char on the screen. The
3085 * position must be safe.
3087 static void
3088 WriteLP(x2, y2)
3089 int x2, y2;
3091 struct mchar oldrend;
3093 ASSERT(display);
3094 ASSERT(D_lp_missing);
3095 oldrend = D_rend;
3096 debug2("WriteLP(%d,%d)\n", x2, y2);
3097 #ifdef DW_CHARS
3098 if (D_lpchar.mbcs)
3100 if (x2 > 0)
3101 x2--;
3102 else
3103 D_lpchar = mchar_blank;
3105 #endif
3106 /* Can't use PutChar */
3107 GotoPos(x2, y2);
3108 SetRendition(&D_lpchar);
3109 PUTCHAR(D_lpchar.image);
3110 #ifdef DW_CHARS
3111 if (D_lpchar.mbcs)
3112 PUTCHAR(D_lpchar.mbcs);
3113 #endif
3114 D_lp_missing = 0;
3115 SetRendition(&oldrend);
3118 void
3119 ClearLine(oml, y, from, to, bce)
3120 struct mline *oml;
3121 int from, to, y, bce;
3123 int x;
3124 #ifdef COLOR
3125 struct mchar bcechar;
3126 #endif
3128 debug3("ClearLine %d,%d-%d\n", y, from, to);
3129 if (D_UT) /* Safe to erase ? */
3130 SetRendition(&mchar_null);
3131 #ifdef COLOR
3132 if (D_BE)
3133 SetBackColor(bce);
3134 #endif
3135 if (from == 0 && D_CB && (to != D_width - 1 || (D_x == to && D_y == y)) && (!bce || D_BE))
3137 GotoPos(to, y);
3138 AddCStr(D_CB);
3139 return;
3141 if (to == D_width - 1 && D_CE && (!bce || D_BE))
3143 GotoPos(from, y);
3144 AddCStr(D_CE);
3145 return;
3147 if (oml == 0)
3148 oml = &mline_null;
3149 #ifdef COLOR
3150 if (!bce)
3152 DisplayLine(oml, &mline_blank, y, from, to);
3153 return;
3155 bcechar = mchar_blank;
3156 rend_setbg(&bcechar, bce);
3157 for (x = from; x <= to; x++)
3158 copy_mchar2mline(&bcechar, &mline_old, x);
3159 DisplayLine(oml, &mline_old, y, from, to);
3160 #else
3161 DisplayLine(oml, &mline_blank, y, from, to);
3162 #endif
3165 void
3166 DisplayLine(oml, ml, y, from, to)
3167 struct mline *oml, *ml;
3168 int from, to, y;{
3170 register int x;
3171 int last2flag = 0, delete_lp = 0;
3173 ASSERT(display);
3174 ASSERT(y >= 0 && y < D_height);
3175 ASSERT(from >= 0 && from < D_width);
3176 ASSERT(to >= 0 && to < D_width);
3177 if (!D_CLP && y == D_bot && to == D_width - 1)
3179 if (D_lp_missing || !cmp_mline(oml, ml, to))
3181 #ifdef DW_CHARS
3182 if ((D_IC || D_IM) && from < to && !dw_left(ml, to, D_encoding))
3183 #else
3184 if ((D_IC || D_IM) && from < to)
3185 #endif
3187 last2flag = 1;
3188 D_lp_missing = 0;
3189 to--;
3191 else
3193 delete_lp = !cmp_mchar_mline(&mchar_blank, oml, to) && (D_CE || D_DC || D_CDC);
3194 D_lp_missing = !cmp_mchar_mline(&mchar_blank, ml, to);
3195 copy_mline2mchar(&D_lpchar, ml, to);
3198 to--;
3200 #ifdef DW_CHARS
3201 if (D_mbcs)
3203 /* finish dw-char (can happen after a wrap) */
3204 debug("DisplayLine finishing kanji\n");
3205 SetRenditionMline(ml, from);
3206 PUTCHAR(ml->image[from]);
3207 from++;
3209 #endif
3210 for (x = from; x <= to; x++)
3212 #if 0 /* no longer needed */
3213 if (x || D_x != D_width || D_y != y - 1)
3214 #endif
3216 if (x < to || x != D_width - 1 || ml->image[x + 1])
3217 if (cmp_mline(oml, ml, x))
3218 continue;
3219 GotoPos(x, y);
3221 #ifdef DW_CHARS
3222 if (dw_right(ml, x, D_encoding))
3224 x--;
3225 debug1("DisplayLine on right side of dw char- x now %d\n", x);
3226 GotoPos(x, y);
3228 if (x == to && dw_left(ml, x, D_encoding))
3229 break; /* don't start new kanji */
3230 #endif
3231 SetRenditionMline(ml, x);
3232 PUTCHAR(ml->image[x]);
3233 #ifdef DW_CHARS
3234 if (dw_left(ml, x, D_encoding))
3235 PUTCHAR(ml->image[++x]);
3236 #endif
3238 #if 0 /* not needed any longer */
3239 /* compare != 0 because ' ' can happen when clipping occures */
3240 if (to == D_width - 1 && y < D_height - 1 && D_x == D_width && ml->image[to + 1])
3241 GotoPos(0, y + 1);
3242 #endif
3243 if (last2flag)
3245 GotoPos(x, y);
3246 SetRenditionMline(ml, x + 1);
3247 PUTCHAR(ml->image[x + 1]);
3248 GotoPos(x, y);
3249 SetRenditionMline(ml, x);
3250 INSERTCHAR(ml->image[x]);
3252 else if (delete_lp)
3254 if (D_UT)
3255 SetRendition(&mchar_null);
3256 if (D_DC)
3257 AddCStr(D_DC);
3258 else if (D_CDC)
3259 AddCStr2(D_CDC, 1);
3260 else if (D_CE)
3261 AddCStr(D_CE);
3265 void
3266 PutChar(c, x, y)
3267 struct mchar *c;
3268 int x, y;
3270 GotoPos(x, y);
3271 SetRendition(c);
3272 PUTCHARLP(c->image);
3273 #ifdef DW_CHARS
3274 if (c->mbcs)
3276 # ifdef UTF8
3277 if (D_encoding == UTF8)
3278 D_rend.font = 0;
3279 # endif
3280 PUTCHARLP(c->mbcs);
3282 #endif
3285 void
3286 InsChar(c, x, xe, y, oml)
3287 struct mchar *c;
3288 int x, xe, y;
3289 struct mline *oml;
3291 GotoPos(x, y);
3292 if (y == D_bot && !D_CLP)
3294 if (x == D_width - 1)
3296 D_lp_missing = 1;
3297 D_lpchar = *c;
3298 return;
3300 if (xe == D_width - 1)
3301 D_lp_missing = 0;
3303 if (x == xe)
3305 SetRendition(c);
3306 PUTCHARLP(c->image);
3307 return;
3309 if (!(D_IC || D_CIC || D_IM) || xe != D_width - 1)
3311 RefreshLine(y, x, xe, 0);
3312 GotoPos(x + 1, y);
3313 /* UpdateLine(oml, y, x, xe); */
3314 return;
3316 InsertMode(1);
3317 if (!D_insert)
3319 #ifdef DW_CHARS
3320 if (c->mbcs && D_IC)
3321 AddCStr(D_IC);
3322 if (D_IC)
3323 AddCStr(D_IC);
3324 else
3325 AddCStr2(D_CIC, c->mbcs ? 2 : 1);
3326 #else
3327 if (D_IC)
3328 AddCStr(D_IC);
3329 else
3330 AddCStr2(D_CIC, 1);
3331 #endif
3333 SetRendition(c);
3334 RAW_PUTCHAR(c->image);
3335 #ifdef DW_CHARS
3336 if (c->mbcs)
3338 # ifdef UTF8
3339 if (D_encoding == UTF8)
3340 D_rend.font = 0;
3341 # endif
3342 if (D_x == D_width - 1)
3343 PUTCHARLP(c->mbcs);
3344 else
3345 RAW_PUTCHAR(c->mbcs);
3347 #endif
3350 void
3351 WrapChar(c, x, y, xs, ys, xe, ye, ins)
3352 struct mchar *c;
3353 int x, y;
3354 int xs, ys, xe, ye;
3355 int ins;
3357 int bce;
3359 #ifdef COLOR
3360 bce = rend_getbg(c);
3361 #else
3362 bce = 0;
3363 #endif
3364 debug("WrapChar:");
3365 debug2(" x %d y %d", x, y);
3366 debug2(" Dx %d Dy %d", D_x, D_y);
3367 debug2(" xs %d ys %d", xs, ys);
3368 debug3(" xe %d ye %d ins %d\n", xe, ye, ins);
3369 if (xs != 0 || x != D_width || !D_AM)
3371 if (y == ye)
3372 ScrollV(xs, ys, xe, ye, 1, bce);
3373 else if (y < D_height - 1)
3374 y++;
3375 if (ins)
3376 InsChar(c, xs, xe, y, 0);
3377 else
3378 PutChar(c, xs, y);
3379 return;
3381 if (y == ye) /* we have to scroll */
3383 debug("- scrolling\n");
3384 ChangeScrollRegion(ys, ye);
3385 if (D_bot != y || D_x != D_width || (!bce && !D_BE))
3387 debug("- have to call ScrollV\n");
3388 ScrollV(xs, ys, xe, ye, 1, bce);
3389 y--;
3392 else if (y == D_bot) /* remove unusable region? */
3393 ChangeScrollRegion(0, D_height - 1);
3394 if (D_x != D_width || D_y != y)
3396 if (D_CLP && y >= 0) /* don't even try if !LP */
3397 RefreshLine(y, D_width - 1, D_width - 1, 0);
3398 debug2("- refresh last char -> x,y now %d,%d\n", D_x, D_y);
3399 if (D_x != D_width || D_y != y) /* sorry, no bonus */
3401 if (y == ye)
3402 ScrollV(xs, ys, xe, ye, 1, bce);
3403 GotoPos(xs, y == ye || y == D_height - 1 ? y : y + 1);
3406 debug("- writeing new char");
3407 if (y != ye && y < D_height - 1)
3408 y++;
3409 if (ins != D_insert)
3410 InsertMode(ins);
3411 if (ins && !D_insert)
3413 InsChar(c, 0, xe, y, 0);
3414 debug2(" -> done with insert (%d,%d)\n", D_x, D_y);
3415 return;
3417 D_y = y;
3418 D_x = 0;
3419 SetRendition(c);
3420 RAW_PUTCHAR(c->image);
3421 #ifdef DW_CHARS
3422 if (c->mbcs)
3424 # ifdef UTF8
3425 if (D_encoding == UTF8)
3426 D_rend.font = 0;
3427 # endif
3428 RAW_PUTCHAR(c->mbcs);
3430 #endif
3431 debug2(" -> done (%d,%d)\n", D_x, D_y);
3435 ResizeDisplay(wi, he)
3436 int wi, he;
3438 ASSERT(display);
3439 debug2("ResizeDisplay: to (%d,%d).\n", wi, he);
3440 if (D_width == wi && D_height == he)
3442 debug("ResizeDisplay: No change\n");
3443 return 0;
3445 if (D_width != wi && (D_height == he || !D_CWS) && D_CZ0 && (wi == Z0width || wi == Z1width))
3447 debug("ResizeDisplay: using Z0/Z1\n");
3448 AddCStr(wi == Z0width ? D_CZ0 : D_CZ1);
3449 ChangeScreenSize(wi, D_height, 0);
3450 return (he == D_height) ? 0 : -1;
3452 if (D_CWS)
3454 debug("ResizeDisplay: using WS\n");
3455 AddCStr(tgoto(D_CWS, wi, he));
3456 ChangeScreenSize(wi, he, 0);
3457 return 0;
3459 return -1;
3462 void
3463 ChangeScrollRegion(newtop, newbot)
3464 int newtop, newbot;
3466 if (display == 0)
3467 return;
3468 if (newtop == newbot)
3469 return; /* xterm etc can't do it */
3470 if (newtop == -1)
3471 newtop = 0;
3472 if (newbot == -1)
3473 newbot = D_height - 1;
3474 if (D_CS == 0)
3476 D_top = 0;
3477 D_bot = D_height - 1;
3478 return;
3480 if (D_top == newtop && D_bot == newbot)
3481 return;
3482 debug2("ChangeScrollRegion: (%d - %d)\n", newtop, newbot);
3483 AddCStr(tgoto(D_CS, newbot, newtop));
3484 D_top = newtop;
3485 D_bot = newbot;
3486 D_y = D_x = -1; /* Just in case... */
3489 #ifdef RXVT_OSC
3490 void
3491 SetXtermOSC(i, s)
3492 int i;
3493 char *s;
3495 static char oscs[] = "1;\000\00020;\00039;\00049;\000";
3497 ASSERT(display);
3498 if (!D_CXT)
3499 return;
3500 if (!s)
3501 s = "";
3502 if (!D_xtermosc[i] && !*s)
3503 return;
3504 if (i == 0 && !*s)
3505 s = "screen"; /* always set icon name */
3506 if (i == 1 && !*s)
3507 s = ""; /* no background */
3508 if (i == 2 && !*s)
3509 s = "black"; /* black text */
3510 if (i == 3 && !*s)
3511 s = "white"; /* on white background */
3512 D_xtermosc[i] = 1;
3513 AddStr("\033]");
3514 AddStr(oscs + i * 4);
3515 AddStr(s);
3516 AddChar(7);
3519 void
3520 ClearAllXtermOSC()
3522 int i;
3523 for (i = 3; i >= 0; i--)
3524 SetXtermOSC(i, 0);
3526 #endif
3529 * Output buffering routines
3532 void
3533 AddStr(str)
3534 char *str;
3536 register char c;
3538 ASSERT(display);
3540 #ifdef UTF8
3541 if (D_encoding == UTF8)
3543 while ((c = *str++))
3544 AddUtf8((unsigned char)c);
3545 return;
3547 #endif
3548 while ((c = *str++))
3549 AddChar(c);
3552 void
3553 AddStrn(str, n)
3554 char *str;
3555 int n;
3557 register char c;
3559 ASSERT(display);
3560 #ifdef UTF8
3561 if (D_encoding == UTF8)
3563 while ((c = *str++) && n-- > 0)
3564 AddUtf8((unsigned char)c);
3566 else
3567 #endif
3568 while ((c = *str++) && n-- > 0)
3569 AddChar(c);
3570 while (n-- > 0)
3571 AddChar(' ');
3574 void
3575 Flush()
3577 register int l;
3578 register char *p;
3580 ASSERT(display);
3581 l = D_obufp - D_obuf;
3582 debug1("Flush(): %d\n", l);
3583 if (l == 0)
3584 return;
3585 ASSERT(l + D_obuffree == D_obuflen);
3586 if (D_userfd < 0)
3588 D_obuffree += l;
3589 D_obufp = D_obuf;
3590 return;
3592 p = D_obuf;
3593 if (fcntl(D_userfd, F_SETFL, 0))
3594 debug1("Warning: BLOCK fcntl failed: %d\n", errno);
3595 while (l)
3597 register int wr;
3598 wr = write(D_userfd, p, l);
3599 if (wr <= 0)
3601 if (errno == EINTR)
3602 continue;
3603 debug1("Writing to display: %d\n", errno);
3604 wr = l;
3606 if (!display)
3607 return;
3608 D_obuffree += wr;
3609 p += wr;
3610 l -= wr;
3612 D_obuffree += l;
3613 D_obufp = D_obuf;
3614 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
3615 debug1("Warning: NBLOCK fcntl failed: %d\n", errno);
3616 if (D_blocked == 1)
3617 D_blocked = 0;
3618 D_blocked_fuzz = 0;
3621 void
3622 freetty()
3624 if (D_userfd >= 0)
3625 close(D_userfd);
3626 debug1("did freetty %d\n", D_userfd);
3627 D_userfd = -1;
3628 D_obufp = 0;
3629 D_obuffree = 0;
3630 if (D_obuf)
3631 free(D_obuf);
3632 D_obuf = 0;
3633 D_obuflen = 0;
3634 D_obuflenmax = -D_obufmax;
3635 D_blocked = 0;
3636 D_blocked_fuzz = 0;
3640 * Asynchronous output routines by
3641 * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
3644 void
3645 Resize_obuf()
3647 register int ind;
3649 ASSERT(display);
3650 if (D_status_obuffree >= 0)
3652 ASSERT(D_obuffree == -1);
3653 if (!D_status_bell)
3655 struct timeval now;
3656 int ti;
3657 gettimeofday(&now, NULL);
3658 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
3659 if (ti < MsgMinWait)
3660 DisplaySleep1000(MsgMinWait - ti, 0);
3662 RemoveStatus();
3663 if (--D_obuffree > 0) /* redo AddChar decrement */
3664 return;
3666 if (D_obuflen && D_obuf)
3668 ind = D_obufp - D_obuf;
3669 D_obuflen += GRAIN;
3670 D_obuffree += GRAIN;
3671 D_obuf = realloc(D_obuf, D_obuflen);
3673 else
3675 ind = 0;
3676 D_obuflen = GRAIN;
3677 D_obuffree = GRAIN;
3678 D_obuf = malloc(D_obuflen);
3680 if (!D_obuf)
3681 Panic(0, "Out of memory");
3682 D_obufp = D_obuf + ind;
3683 D_obuflenmax = D_obuflen - D_obufmax;
3684 debug1("ResizeObuf: resized to %d\n", D_obuflen);
3687 void
3688 DisplaySleep1000(n, eat)
3689 int n;
3690 int eat;
3692 char buf;
3693 fd_set r;
3694 struct timeval t;
3696 if (n <= 0)
3697 return;
3698 if (!display)
3700 debug("DisplaySleep has no display sigh\n");
3701 sleep1000(n);
3702 return;
3704 t.tv_usec = (n % 1000) * 1000;
3705 t.tv_sec = n / 1000;
3706 FD_ZERO(&r);
3707 FD_SET(D_userfd, &r);
3708 if (select(FD_SETSIZE, &r, (fd_set *)0, (fd_set *)0, &t) > 0)
3710 debug("display activity stopped sleep\n");
3711 if (eat)
3712 read(D_userfd, &buf, 1);
3714 debug2("DisplaySleep(%d) ending, eat was %d\n", n, eat);
3717 #ifdef AUTO_NUKE
3718 void
3719 NukePending()
3720 {/* Nuke pending output in current display, clear screen */
3721 register int len;
3722 int oldtop = D_top, oldbot = D_bot;
3723 struct mchar oldrend;
3724 int oldkeypad = D_keypad, oldcursorkeys = D_cursorkeys;
3725 int oldcurvis = D_curvis;
3726 int oldmouse = D_mouse;
3728 oldrend = D_rend;
3729 len = D_obufp - D_obuf;
3730 debug1("NukePending: nuking %d chars\n", len);
3732 /* Throw away any output that we can... */
3733 # ifdef POSIX
3734 tcflush(D_userfd, TCOFLUSH);
3735 # else
3736 # ifdef TCFLSH
3737 (void) ioctl(D_userfd, TCFLSH, (char *) 1);
3738 # endif
3739 # endif
3741 D_obufp = D_obuf;
3742 D_obuffree += len;
3743 D_top = D_bot = -1;
3744 AddCStr(D_TI);
3745 AddCStr(D_IS);
3746 /* Turn off all attributes. (Tim MacKenzie) */
3747 if (D_ME)
3748 AddCStr(D_ME);
3749 else
3751 #ifdef COLOR
3752 if (D_hascolor)
3753 AddStr("\033[m"); /* why is D_ME not set? */
3754 #endif
3755 AddCStr(D_SE);
3756 AddCStr(D_UE);
3758 /* Check for toggle */
3759 if (D_IM && strcmp(D_IM, D_EI))
3760 AddCStr(D_EI);
3761 D_insert = 0;
3762 /* Check for toggle */
3763 #ifdef MAPKEYS
3764 if (D_KS && strcmp(D_KS, D_KE))
3765 AddCStr(D_KS);
3766 if (D_CCS && strcmp(D_CCS, D_CCE))
3767 AddCStr(D_CCS);
3768 #else
3769 if (D_KS && strcmp(D_KS, D_KE))
3770 AddCStr(D_KE);
3771 D_keypad = 0;
3772 if (D_CCS && strcmp(D_CCS, D_CCE))
3773 AddCStr(D_CCE);
3774 D_cursorkeys = 0;
3775 #endif
3776 AddCStr(D_CE0);
3777 D_rend = mchar_null;
3778 D_atyp = 0;
3779 AddCStr(D_DS);
3780 D_hstatus = 0;
3781 AddCStr(D_VE);
3782 D_curvis = 0;
3783 ChangeScrollRegion(oldtop, oldbot);
3784 SetRendition(&oldrend);
3785 KeypadMode(oldkeypad);
3786 CursorkeysMode(oldcursorkeys);
3787 CursorVisibility(oldcurvis);
3788 MouseMode(oldmouse);
3789 if (D_CWS)
3791 debug("ResizeDisplay: using WS\n");
3792 AddCStr(tgoto(D_CWS, D_width, D_height));
3794 else if (D_CZ0 && (D_width == Z0width || D_width == Z1width))
3796 debug("ResizeDisplay: using Z0/Z1\n");
3797 AddCStr(D_width == Z0width ? D_CZ0 : D_CZ1);
3800 #endif /* AUTO_NUKE */
3802 #ifdef linux
3803 /* linux' select can't handle flow control, so wait 100ms if
3804 * we get EAGAIN
3806 static void
3807 disp_writeev_eagain(ev, data)
3808 struct event *ev;
3809 char *data;
3811 display = (struct display *)data;
3812 evdeq(&D_writeev);
3813 D_writeev.type = EV_WRITE;
3814 D_writeev.handler = disp_writeev_fn;
3815 evenq(&D_writeev);
3817 #endif
3819 static void
3820 disp_writeev_fn(ev, data)
3821 struct event *ev;
3822 char *data;
3824 int len, size = OUTPUT_BLOCK_SIZE;
3826 display = (struct display *)data;
3827 len = D_obufp - D_obuf;
3828 if (len < size)
3829 size = len;
3830 ASSERT(len >= 0);
3831 size = write(D_userfd, D_obuf, size);
3832 if (size >= 0)
3834 len -= size;
3835 if (len)
3837 bcopy(D_obuf + size, D_obuf, len);
3838 debug2("ASYNC: wrote %d - remaining %d\n", size, len);
3840 D_obufp -= size;
3841 D_obuffree += size;
3842 if (D_blocked_fuzz)
3844 D_blocked_fuzz -= size;
3845 if (D_blocked_fuzz < 0)
3846 D_blocked_fuzz = 0;
3848 if (D_blockedev.queued)
3850 if (D_obufp - D_obuf > D_obufmax / 2)
3852 debug2("%s: resetting timeout to %g secs\n", D_usertty, D_nonblock/1000.);
3853 SetTimeout(&D_blockedev, D_nonblock);
3855 else
3857 debug1("%s: deleting blocked timeout\n", D_usertty);
3858 evdeq(&D_blockedev);
3861 if (D_blocked == 1 && D_obuf == D_obufp)
3863 /* empty again, restart output */
3864 debug1("%s: buffer empty, unblocking\n", D_usertty);
3865 D_blocked = 0;
3866 Activate(D_fore ? D_fore->w_norefresh : 0);
3867 D_blocked_fuzz = D_obufp - D_obuf;
3870 else
3872 #ifdef linux
3873 /* linux flow control is badly broken */
3874 if (errno == EAGAIN)
3876 evdeq(&D_writeev);
3877 D_writeev.type = EV_TIMEOUT;
3878 D_writeev.handler = disp_writeev_eagain;
3879 SetTimeout(&D_writeev, 100);
3880 evenq(&D_writeev);
3882 #endif
3883 if (errno != EINTR && errno != EAGAIN)
3884 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3885 if (errno != EWOULDBLOCK)
3886 #endif
3887 Msg(errno, "Error writing output to display");
3891 static void
3892 disp_readev_fn(ev, data)
3893 struct event *ev;
3894 char *data;
3896 int size;
3897 char buf[IOSIZE];
3898 struct canvas *cv;
3900 display = (struct display *)data;
3902 /* Hmmmm... a bit ugly... */
3903 if (D_forecv)
3904 for (cv = D_forecv->c_layer->l_cvlist; cv; cv = cv->c_lnext)
3906 display = cv->c_display;
3907 if (D_status == STATUS_ON_WIN)
3908 RemoveStatus();
3911 display = (struct display *)data;
3912 if (D_fore == 0)
3913 size = IOSIZE;
3914 else
3916 #ifdef PSEUDOS
3917 if (W_UWP(D_fore))
3918 size = sizeof(D_fore->w_pwin->p_inbuf) - D_fore->w_pwin->p_inlen;
3919 else
3920 #endif
3921 size = sizeof(D_fore->w_inbuf) - D_fore->w_inlen;
3924 if (size > IOSIZE)
3925 size = IOSIZE;
3926 if (size <= 0)
3927 size = 1; /* Always allow one char for command keys */
3929 size = read(D_userfd, buf, size);
3930 if (size < 0)
3932 if (errno == EINTR || errno == EAGAIN)
3933 return;
3934 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3935 if (errno == EWOULDBLOCK)
3936 return;
3937 #endif
3938 debug1("Read error: %d - hangup!\n", errno);
3939 Hangup();
3940 sleep(1);
3941 return;
3943 else if (size == 0)
3945 debug("Found EOF - hangup!\n");
3946 Hangup();
3947 sleep(1);
3948 return;
3950 if (D_blocked == 4)
3952 D_blocked = 0;
3953 #ifdef BLANKER_PRG
3954 KillBlanker();
3955 #endif
3956 Activate(D_fore ? D_fore->w_norefresh : 0);
3957 ResetIdle();
3958 return;
3960 #ifdef ZMODEM
3961 if (D_blocked > 1) /* 2, 3 */
3963 char *bufp;
3964 struct win *p;
3966 flayer = 0;
3967 for (p = windows; p ; p = p->w_next)
3968 if (p->w_zdisplay == display)
3970 flayer = &p->w_layer;
3971 bufp = buf;
3972 while (size > 0)
3973 LayProcess(&bufp, &size);
3974 return;
3976 debug("zmodem window gone, deblocking display");
3977 zmodem_abort(0, display);
3979 #endif
3980 if (idletimo > 0)
3981 ResetIdle();
3982 if (D_fore)
3983 D_fore->w_lastdisp = display;
3984 if (D_mouse && D_forecv)
3986 unsigned char *bp = (unsigned char *)buf;
3987 int x, y, i = size;
3989 /* XXX this assumes that the string is read in as a whole... */
3990 for (i = size; i > 0; i--, bp++)
3992 if (i > 5 && bp[0] == 033 && bp[1] == '[' && bp[2] == 'M')
3994 bp++;
3995 i--;
3997 else if (i < 5 || bp[0] != 0233 || bp[1] != 'M')
3998 continue;
3999 x = bp[3] - 33;
4000 y = bp[4] - 33;
4001 if (x >= D_forecv->c_xs && x <= D_forecv->c_xe && y >= D_forecv->c_ys && y <= D_forecv->c_ye)
4003 x -= D_forecv->c_xoff;
4004 y -= D_forecv->c_yoff;
4005 if (x >= 0 && x < D_forecv->c_layer->l_width && y >= 0 && y < D_forecv->c_layer->l_height)
4007 bp[3] = x + 33;
4008 bp[4] = y + 33;
4009 i -= 4;
4010 bp += 4;
4011 continue;
4014 if (bp[0] == '[')
4016 bcopy((char *)bp + 1, (char *)bp, i);
4017 bp--;
4018 size--;
4020 if (i > 5)
4021 bcopy((char *)bp + 5, (char *)bp, i - 5);
4022 bp--;
4023 i -= 4;
4024 size -= 5;
4027 #ifdef ENCODINGS
4028 if (D_encoding != (D_forecv ? D_forecv->c_layer->l_encoding : 0))
4030 int i, j, c, enc;
4031 char buf2[IOSIZE * 2 + 10];
4032 enc = D_forecv ? D_forecv->c_layer->l_encoding : 0;
4033 for (i = j = 0; i < size; i++)
4035 c = ((unsigned char *)buf)[i];
4036 c = DecodeChar(c, D_encoding, &D_decodestate);
4037 if (c == -2)
4038 i--; /* try char again */
4039 if (c < 0)
4040 continue;
4041 if (pastefont)
4043 int font = 0;
4044 j += EncodeChar(buf2 + j, c, enc, &font);
4045 j += EncodeChar(buf2 + j, -1, enc, &font);
4047 else
4048 j += EncodeChar(buf2 + j, c, enc, 0);
4049 if (j > (int)sizeof(buf2) - 10) /* just in case... */
4050 break;
4052 (*D_processinput)(buf2, j);
4053 return;
4055 #endif
4056 (*D_processinput)(buf, size);
4059 static void
4060 disp_status_fn(ev, data)
4061 struct event *ev;
4062 char *data;
4064 display = (struct display *)data;
4065 debug1("disp_status_fn for display %x\n", (int)display);
4066 if (D_status)
4067 RemoveStatus();
4070 static void
4071 disp_hstatus_fn(ev, data)
4072 struct event *ev;
4073 char *data;
4075 display = (struct display *)data;
4076 if (D_status == STATUS_ON_HS)
4078 SetTimeout(ev, 1);
4079 evenq(ev);
4080 return;
4082 RefreshHStatus();
4085 static void
4086 disp_blocked_fn(ev, data)
4087 struct event *ev;
4088 char *data;
4090 struct win *p;
4092 display = (struct display *)data;
4093 debug1("blocked timeout %s\n", D_usertty);
4094 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
4096 debug("stopping output to display\n");
4097 D_blocked = 1;
4098 /* re-enable all windows */
4099 for (p = windows; p; p = p->w_next)
4100 if (p->w_readev.condneg == &D_obuflenmax)
4102 debug1("freeing window #%d\n", p->w_number);
4103 p->w_readev.condpos = p->w_readev.condneg = 0;
4108 static void
4109 cv_winid_fn(ev, data)
4110 struct event *ev;
4111 char *data;
4113 int ox, oy;
4114 struct canvas *cv = (struct canvas *)data;
4116 display = cv->c_display;
4117 if (D_status == STATUS_ON_WIN)
4119 SetTimeout(ev, 1);
4120 evenq(ev);
4121 return;
4123 ox = D_x;
4124 oy = D_y;
4125 if (cv->c_ye + 1 < D_height)
4126 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
4127 if (ox != -1 && oy != -1)
4128 GotoPos(ox, oy);
4131 #ifdef MAPKEYS
4132 static void
4133 disp_map_fn(ev, data)
4134 struct event *ev;
4135 char *data;
4137 char *p;
4138 int l, i;
4139 unsigned char *q;
4140 display = (struct display *)data;
4141 debug("Flushing map sequence\n");
4142 if (!(l = D_seql))
4143 return;
4144 p = (char *)D_seqp - l;
4145 D_seqp = D_kmaps + 3;
4146 D_seql = 0;
4147 if ((q = D_seqh) != 0)
4149 D_seqh = 0;
4150 i = q[0] << 8 | q[1];
4151 i &= ~KMAP_NOTIMEOUT;
4152 debug1("Mapping former hit #%d - ", i);
4153 debug2("%d(%s) - ", q[2], q + 3);
4154 if (StuffKey(i))
4155 ProcessInput2((char *)q + 3, q[2]);
4156 if (display == 0)
4157 return;
4158 l -= q[2];
4159 p += q[2];
4161 else
4162 D_dontmap = 1;
4163 ProcessInput(p, l);
4165 #endif
4167 static void
4168 disp_idle_fn(ev, data)
4169 struct event *ev;
4170 char *data;
4172 struct display *olddisplay;
4173 display = (struct display *)data;
4174 debug("idle timeout\n");
4175 if (idletimo <= 0 || idleaction.nr == RC_ILLEGAL)
4176 return;
4177 olddisplay = display;
4178 flayer = D_forecv->c_layer;
4179 fore = D_fore;
4180 DoAction(&idleaction, -1);
4181 if (idleaction.nr == RC_BLANKER)
4182 return;
4183 for (display = displays; display; display = display->d_next)
4184 if (olddisplay == display)
4185 break;
4186 if (display)
4187 ResetIdle();
4190 void
4191 ResetIdle()
4193 if (idletimo > 0)
4195 SetTimeout(&D_idleev, idletimo);
4196 if (!D_idleev.queued)
4197 evenq(&D_idleev);
4199 else
4200 evdeq(&D_idleev);
4204 #ifdef BLANKER_PRG
4206 static void
4207 disp_blanker_fn(ev, data)
4208 struct event *ev;
4209 char *data;
4211 char buf[IOSIZE], *b;
4212 int size;
4214 display = (struct display *)data;
4215 size = read(D_blankerev.fd, buf, IOSIZE);
4216 if (size <= 0)
4218 evdeq(&D_blankerev);
4219 close(D_blankerev.fd);
4220 D_blankerev.fd = -1;
4221 return;
4223 for (b = buf; size; size--)
4224 AddChar(*b++);
4227 void
4228 KillBlanker()
4230 int oldtop = D_top, oldbot = D_bot;
4231 struct mchar oldrend;
4233 if (D_blankerev.fd == -1)
4234 return;
4235 if (D_blocked == 4)
4236 D_blocked = 0;
4237 evdeq(&D_blankerev);
4238 close(D_blankerev.fd);
4239 D_blankerev.fd = -1;
4240 Kill(D_blankerpid, SIGHUP);
4241 D_top = D_bot = -1;
4242 oldrend = D_rend;
4243 if (D_ME)
4245 AddCStr(D_ME);
4246 AddCStr(D_ME);
4248 else
4250 #ifdef COLOR
4251 if (D_hascolor)
4252 AddStr("\033[m\033[m"); /* why is D_ME not set? */
4253 #endif
4254 AddCStr(D_SE);
4255 AddCStr(D_UE);
4257 AddCStr(D_VE);
4258 AddCStr(D_CE0);
4259 D_rend = mchar_null;
4260 D_atyp = 0;
4261 D_curvis = 0;
4262 D_x = D_y = -1;
4263 ChangeScrollRegion(oldtop, oldbot);
4264 SetRendition(&oldrend);
4265 ClearAll();
4268 void
4269 RunBlanker(cmdv)
4270 char **cmdv;
4272 char *m;
4273 int pid;
4274 int slave = -1;
4275 char termname[30];
4276 #ifndef TIOCSWINSZ
4277 char libuf[20], cobuf[20];
4278 #endif
4279 char **np;
4281 strcpy(termname, "TERM=");
4282 strncpy(termname + 5, D_termname, sizeof(termname) - 6);
4283 termname[sizeof(termname) - 1] = 0;
4284 KillBlanker();
4285 D_blankerpid = -1;
4286 if ((D_blankerev.fd = OpenPTY(&m)) == -1)
4288 Msg(0, "OpenPty failed");
4289 return;
4291 #ifdef O_NOCTTY
4292 if (pty_preopen)
4294 if ((slave = open(m, O_RDWR|O_NOCTTY)) == -1)
4296 Msg(errno, "%s", m);
4297 close(D_blankerev.fd);
4298 D_blankerev.fd = -1;
4299 return;
4302 #endif
4303 switch (pid = (int)fork())
4305 case -1:
4306 Msg(errno, "fork");
4307 close(D_blankerev.fd);
4308 D_blankerev.fd = -1;
4309 return;
4310 case 0:
4311 displays = 0;
4312 #ifdef DEBUG
4313 if (dfp && dfp != stderr)
4315 fclose(dfp);
4316 dfp = 0;
4318 #endif
4319 if (setgid(real_gid) || setuid(real_uid))
4320 Panic(errno, "setuid/setgid");
4321 brktty(D_userfd);
4322 freetty();
4323 close(0);
4324 close(1);
4325 close(2);
4326 closeallfiles(slave);
4327 if (open(m, O_RDWR))
4328 Panic(errno, "Cannot open %s", m);
4329 dup(0);
4330 dup(0);
4331 if (slave != -1)
4332 close(slave);
4333 InitPTY(0);
4334 fgtty(0);
4335 SetTTY(0, &D_OldMode);
4336 np = NewEnv + 3;
4337 *np++ = NewEnv[0];
4338 *np++ = termname;
4339 #ifdef TIOCSWINSZ
4340 glwz.ws_col = D_width;
4341 glwz.ws_row = D_height;
4342 (void)ioctl(0, TIOCSWINSZ, (char *)&glwz);
4343 #else
4344 sprintf(libuf, "LINES=%d", D_height);
4345 sprintf(cobuf, "COLUMNS=%d", D_width);
4346 *np++ = libuf;
4347 *np++ = cobuf;
4348 #endif
4349 #ifdef SIGPIPE
4350 signal(SIGPIPE, SIG_DFL);
4351 #endif
4352 display = 0;
4353 execvpe(*cmdv, cmdv, NewEnv + 3);
4354 Panic(errno, *cmdv);
4355 default:
4356 break;
4358 D_blankerpid = pid;
4359 evenq(&D_blankerev);
4360 D_blocked = 4;
4361 ClearAll();
4364 #endif
4366 struct layout *layouts;
4367 struct layout *laytab[MAXLAY];
4368 struct layout *layout_last, layout_last_marker;
4369 struct layout *layout_attach = &layout_last_marker;
4371 void
4372 FreeLayoutCv(cv)
4373 struct canvas *cv;
4375 struct canvas *cnext, *c = cv;
4376 for (; cv; cv = cnext)
4378 if (cv->c_slperp)
4380 FreeLayoutCv(cv->c_slperp);
4381 free(cv->c_slperp);
4382 cv->c_slperp = 0;
4384 cnext = cv->c_slnext;
4385 cv->c_slnext = 0;
4386 if (cv != c)
4387 free(cv);
4391 static void
4392 DupLayoutCv(cvf, cvt, save)
4393 struct canvas *cvf, *cvt;
4394 int save;
4396 while(cvf)
4398 cvt->c_slorient = cvf->c_slorient;
4399 cvt->c_slweight = cvf->c_slweight;
4400 if (cvf == D_forecv)
4401 D_forecv = cvt;
4402 if (!save)
4404 cvt->c_display = display;
4405 if (!cvf->c_slperp)
4407 cvt->c_captev.type = EV_TIMEOUT;
4408 cvt->c_captev.data = (char *)cvt;
4409 cvt->c_captev.handler = cv_winid_fn;
4410 cvt->c_blank.l_cvlist = 0;
4411 cvt->c_blank.l_layfn = &BlankLf;
4412 cvt->c_blank.l_bottom = &cvt->c_blank;
4414 cvt->c_layer = cvf->c_layer;
4416 else
4418 struct win *p = cvf->c_layer ? Layer2Window(cvf->c_layer) : 0;
4419 cvt->c_layer = p ? &p->w_layer : 0;
4421 if (cvf->c_slperp)
4423 cvt->c_slperp = (struct canvas *)calloc(1, sizeof(struct canvas));
4424 cvt->c_slperp->c_slback = cvt;
4425 CanvasInitBlank(cvt->c_slperp);
4426 DupLayoutCv(cvf->c_slperp, cvt->c_slperp, save);
4428 if (cvf->c_slnext)
4430 cvt->c_slnext = (struct canvas *)calloc(1, sizeof(struct canvas));
4431 cvt->c_slnext->c_slprev = cvt;
4432 cvt->c_slnext->c_slback = cvt->c_slback;
4433 CanvasInitBlank(cvt->c_slnext);
4435 cvf = cvf->c_slnext;
4436 cvt = cvt->c_slnext;
4440 void
4441 PutWindowCv(cv)
4442 struct canvas *cv;
4444 struct win *p;
4445 for (; cv; cv = cv->c_slnext)
4447 if (cv->c_slperp)
4449 PutWindowCv(cv->c_slperp);
4450 continue;
4452 p = cv->c_layer ? (struct win *)cv->c_layer->l_data : 0;
4453 cv->c_layer = 0;
4454 SetCanvasWindow(cv, p);
4458 struct layout *
4459 CreateLayout(title, startat)
4460 char *title;
4461 int startat;
4463 struct layout *lay;
4464 int i;
4466 if (startat >= MAXLAY || startat < 0)
4467 startat = 0;
4468 for (i = startat; ;)
4470 if (!laytab[i])
4471 break;
4472 if (++i == MAXLAY)
4473 i = 0;
4474 if (i == startat)
4476 Msg(0, "No more layouts\n");
4477 return 0;
4480 lay = (struct layout *)calloc(1, sizeof(*lay));
4481 lay->lay_title = SaveStr(title);
4482 lay->lay_autosave = 1;
4483 lay->lay_number = i;
4484 laytab[i] = lay;
4485 lay->lay_next = layouts;
4486 layouts = lay;
4487 return lay;
4490 void
4491 SaveLayout(name, cv)
4492 char *name;
4493 struct canvas *cv;
4495 struct layout *lay;
4496 struct canvas *fcv;
4497 for (lay = layouts; lay; lay = lay->lay_next)
4498 if (!strcmp(lay->lay_title, name))
4499 break;
4500 if (lay)
4501 FreeLayoutCv(&lay->lay_canvas);
4502 else
4503 lay = CreateLayout(name, 0);
4504 if (!lay)
4505 return;
4506 fcv = D_forecv;
4507 DupLayoutCv(cv, &lay->lay_canvas, 1);
4508 lay->lay_forecv = D_forecv;
4509 D_forecv = fcv;
4510 D_layout = lay;
4513 void
4514 AutosaveLayout(lay)
4515 struct layout *lay;
4517 struct canvas *fcv;
4518 if (!lay || !lay->lay_autosave)
4519 return;
4520 FreeLayoutCv(&lay->lay_canvas);
4521 fcv = D_forecv;
4522 DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
4523 lay->lay_forecv = D_forecv;
4524 D_forecv = fcv;
4527 struct layout *
4528 FindLayout(name)
4529 char *name;
4531 struct layout *lay;
4532 char *s;
4533 int i;
4534 for (i = 0, s = name; *s >= '0' && *s <= '9'; s++)
4535 i = i * 10 + (*s - '0');
4536 if (!*s && s != name && i >= 0 && i < MAXLAY)
4537 return laytab[i];
4538 for (lay = layouts; lay; lay = lay->lay_next)
4539 if (!strcmp(lay->lay_title, name))
4540 break;
4541 return lay;
4544 void
4545 LoadLayout(lay, cv)
4546 struct layout *lay;
4547 struct canvas *cv;
4549 AutosaveLayout(D_layout);
4550 if (!lay)
4552 while (D_canvas.c_slperp)
4553 FreeCanvas(D_canvas.c_slperp);
4554 MakeDefaultCanvas();
4555 SetCanvasWindow(D_forecv, 0);
4556 D_layout = 0;
4557 return;
4559 while (D_canvas.c_slperp)
4560 FreeCanvas(D_canvas.c_slperp);
4561 D_cvlist = 0;
4562 D_forecv = lay->lay_forecv;
4563 DupLayoutCv(&lay->lay_canvas, &D_canvas, 0);
4564 D_canvas.c_ye = D_height - 1 - ((D_canvas.c_slperp && D_canvas.c_slperp->c_slnext) || captionalways) - (D_has_hstatus == HSTATUS_LASTLINE);
4565 ResizeCanvas(&D_canvas);
4566 RecreateCanvasChain();
4567 RethinkDisplayViewports();
4568 PutWindowCv(&D_canvas);
4569 ResizeLayersToCanvases();
4570 D_layout = lay;
4573 void
4574 NewLayout(title, startat)
4575 char *title;
4576 int startat;
4578 struct layout *lay;
4579 struct canvas *fcv;
4581 lay = CreateLayout(title, startat);
4582 if (!lay)
4583 return;
4584 LoadLayout(0, &D_canvas);
4585 fcv = D_forecv;
4586 DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
4587 lay->lay_forecv = D_forecv;
4588 D_forecv = fcv;
4589 D_layout = lay;
4590 lay->lay_autosave = 1;
4593 static char *
4594 AddLayoutsInfo(buf, len, where)
4595 char *buf;
4596 int len;
4597 int where;
4599 char *s, *ss, *t;
4600 struct layout *p, **pp;
4601 int l;
4603 s = ss = buf;
4604 for (pp = laytab; pp < laytab + MAXLAY; pp++)
4606 if (pp - laytab == where && ss == buf)
4607 ss = s;
4608 if ((p = *pp) == 0)
4609 continue;
4610 t = p->lay_title;
4611 l = strlen(t);
4612 if (l > 20)
4613 l = 20;
4614 if (s - buf + l > len - 24)
4615 break;
4616 if (s > buf)
4618 *s++ = ' ';
4619 *s++ = ' ';
4621 sprintf(s, "%d", p->lay_number);
4622 if (p->lay_number == where)
4623 ss = s;
4624 s += strlen(s);
4625 if (display && p == D_layout)
4626 *s++ = '*';
4627 *s++ = ' ';
4628 strncpy(s, t, l);
4629 s += l;
4631 *s = 0;
4632 return ss;
4635 void
4636 ShowLayouts(where)
4637 int where;
4639 char buf[1024];
4640 char *s, *ss;
4642 if (!display)
4643 return;
4644 if (!layouts)
4646 Msg(0, "No layouts defined\n");
4647 return;
4649 if (where == -1 && D_layout)
4650 where = D_layout->lay_number;
4651 ss = AddLayoutsInfo(buf, sizeof(buf), where);
4652 s = buf + strlen(buf);
4653 if (ss - buf > D_width / 2)
4655 ss -= D_width / 2;
4656 if (s - ss < D_width)
4658 ss = s - D_width;
4659 if (ss < buf)
4660 ss = buf;
4663 else
4664 ss = buf;
4665 Msg(0, "%s", ss);
4668 void
4669 RemoveLayout(lay)
4670 struct layout *lay;
4672 struct layout **layp = &layouts;
4674 for (; *layp; layp = &(*layp)->lay_next)
4676 if (*layp == lay)
4678 *layp = lay->lay_next;
4679 break;
4682 laytab[lay->lay_number] = (struct layout *)0;
4684 if (display && D_layout == lay)
4685 D_layout = (struct layout *)0;
4687 FreeLayoutCv(&lay->lay_canvas);
4689 if (lay->lay_title)
4690 free(lay->lay_title);
4691 free(lay);
4693 if (layouts)
4694 LoadLayout((display && D_layout) ? D_layout : *layp ? *layp : layouts,
4695 display ? &D_canvas : (struct canvas *)0);
4696 Activate(0);