Fix canvas resizing for vertical splits.
[screen-lua.git] / src / display.c
blobb9d676edae2dc36bf7f3caff63b0d85abc9e50f0
1 /* Copyright (c) 1993-2002
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 ****************************************************************
24 #include <sys/types.h>
25 #include <signal.h>
26 #include <fcntl.h>
27 #ifndef sun
28 # include <sys/ioctl.h>
29 #endif
31 #include "config.h"
32 #include "screen.h"
33 #include "extern.h"
34 #include "braille.h"
36 static int CountChars __P((int));
37 static int DoAddChar __P((int));
38 static int BlankResize __P((int, int));
39 static int CallRewrite __P((int, int, int, int));
40 static void FreeCanvas __P((struct canvas *));
41 static void disp_readev_fn __P((struct event *, char *));
42 static void disp_writeev_fn __P((struct event *, char *));
43 #ifdef linux
44 static void disp_writeev_eagain __P((struct event *, char *));
45 #endif
46 static void disp_status_fn __P((struct event *, char *));
47 static void disp_hstatus_fn __P((struct event *, char *));
48 static void disp_blocked_fn __P((struct event *, char *));
49 static void cv_winid_fn __P((struct event *, char *));
50 #ifdef MAPKEYS
51 static void disp_map_fn __P((struct event *, char *));
52 #endif
53 static void disp_idle_fn __P((struct event *, char *));
54 #ifdef BLANKER_PRG
55 static void disp_blanker_fn __P((struct event *, char *));
56 #endif
57 static void WriteLP __P((int, int));
58 static void INSERTCHAR __P((int));
59 static void RAW_PUTCHAR __P((int));
60 #ifdef COLOR
61 static void SetBackColor __P((int));
62 #endif
63 static void FreePerp __P((struct canvas *));
64 static struct canvas *AddPerp __P((struct canvas *));
67 extern struct layer *flayer;
68 extern struct win *windows, *fore;
69 extern struct LayFuncs WinLf;
71 extern int use_hardstatus;
72 extern int MsgWait, MsgMinWait;
73 extern int Z0width, Z1width;
74 extern unsigned char *blank, *null;
75 extern struct mline mline_blank, mline_null, mline_old;
76 extern struct mchar mchar_null, mchar_blank, mchar_so;
77 extern struct NewWindow nwin_default;
78 extern struct action idleaction;
80 /* XXX shouldn't be here */
81 extern char *hstatusstring;
82 extern char *captionstring;
84 extern int pastefont;
85 extern int idletimo;
87 #ifdef BLANKER_PRG
88 extern int pty_preopen;
89 #if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
90 extern struct winsize glwz;
91 #endif
92 extern char **NewEnv;
93 extern int real_uid, real_gid;
94 #endif
97 * tputs needs this to calculate the padding
99 #ifndef NEED_OSPEED
100 extern
101 #endif /* NEED_OSPEED */
102 short ospeed;
105 struct display *display, *displays;
106 #ifdef COLOR
107 int attr2color[8][4];
108 int nattr2color;
109 #endif
111 #ifndef MULTI
112 struct display TheDisplay;
113 #endif
116 * The default values
118 int defobuflimit = OBUF_MAX;
119 int defnonblock = -1;
120 #ifdef AUTO_NUKE
121 int defautonuke = 0;
122 #endif
123 int captionalways;
124 int hardstatusemu = HSTATUS_IGNORE;
126 int focusminwidth, focusminheight;
129 * Default layer management
132 void
133 DefProcess(bufp, lenp)
134 char **bufp;
135 int *lenp;
137 *bufp += *lenp;
138 *lenp = 0;
141 void
142 DefRedisplayLine(y, xs, xe, isblank)
143 int y, xs, xe, isblank;
145 if (isblank == 0 && y >= 0)
146 DefClearLine(y, xs, xe, 0);
149 void
150 DefClearLine(y, xs, xe, bce)
151 int y, xs, xe, bce;
153 LClearLine(flayer, y, xs, xe, bce, (struct mline *)0);
156 /*ARGSUSED*/
158 DefRewrite(y, xs, xe, rend, doit)
159 int y, xs, xe, doit;
160 struct mchar *rend;
162 return EXPENSIVE;
165 /*ARGSUSED*/
167 DefResize(wi, he)
168 int wi, he;
170 return -1;
173 void
174 DefRestore()
176 LAY_DISPLAYS(flayer, InsertMode(0));
177 /* ChangeScrollRegion(0, D_height - 1); */
178 LKeypadMode(flayer, 0);
179 LCursorkeysMode(flayer, 0);
180 LCursorVisibility(flayer, 0);
181 LMouseMode(flayer, 0);
182 LSetRendition(flayer, &mchar_null);
183 LSetFlow(flayer, nwin_default.flowflag & FLOW_NOW);
187 * Blank layer management
190 struct LayFuncs BlankLf =
192 DefProcess,
194 DefRedisplayLine,
195 DefClearLine,
196 DefRewrite,
197 BlankResize,
198 DefRestore
201 /*ARGSUSED*/
202 static int
203 BlankResize(wi, he)
204 int wi, he;
206 flayer->l_width = wi;
207 flayer->l_height = he;
208 return 0;
213 * Generate new display, start with a blank layer.
214 * The termcap arrays are not initialised here.
215 * The new display is placed in the displays list.
218 struct display *
219 MakeDisplay(uname, utty, term, fd, pid, Mode)
220 char *uname, *utty, *term;
221 int fd, pid;
222 struct mode *Mode;
224 struct acluser **u;
225 struct baud_values *b;
227 if (!*(u = FindUserPtr(uname)) && UserAdd(uname, (char *)0, u))
228 return 0; /* could not find or add user */
230 #ifdef MULTI
231 if ((display = (struct display *)calloc(1, sizeof(*display))) == 0)
232 return 0;
233 #else
234 if (displays)
235 return 0;
236 bzero((char *)&TheDisplay, sizeof(TheDisplay));
237 display = &TheDisplay;
238 #endif
239 display->d_next = displays;
240 displays = display;
241 D_flow = 1;
242 D_nonblock = defnonblock;
243 D_userfd = fd;
244 D_readev.fd = D_writeev.fd = fd;
245 D_readev.type = EV_READ;
246 D_writeev.type = EV_WRITE;
247 D_readev.data = D_writeev.data = (char *)display;
248 D_readev.handler = disp_readev_fn;
249 D_writeev.handler = disp_writeev_fn;
250 evenq(&D_readev);
251 D_writeev.condpos = &D_obuflen;
252 D_writeev.condneg = &D_obuffree;
253 evenq(&D_writeev);
254 D_statusev.type = EV_TIMEOUT;
255 D_statusev.data = (char *)display;
256 D_statusev.handler = disp_status_fn;
257 D_hstatusev.type = EV_TIMEOUT;
258 D_hstatusev.data = (char *)display;
259 D_hstatusev.handler = disp_hstatus_fn;
260 D_blockedev.type = EV_TIMEOUT;
261 D_blockedev.data = (char *)display;
262 D_blockedev.handler = disp_blocked_fn;
263 D_blockedev.condpos = &D_obuffree;
264 D_blockedev.condneg = &D_obuflenmax;
265 D_hstatusev.handler = disp_hstatus_fn;
266 #ifdef MAPKEYS
267 D_mapev.type = EV_TIMEOUT;
268 D_mapev.data = (char *)display;
269 D_mapev.handler = disp_map_fn;
270 #endif
271 D_idleev.type = EV_TIMEOUT;
272 D_idleev.data = (char *)display;
273 D_idleev.handler = disp_idle_fn;
274 #ifdef BLANKER_PRG
275 D_blankerev.type = EV_READ;
276 D_blankerev.data = (char *)display;
277 D_blankerev.handler = disp_blanker_fn;
278 D_blankerev.fd = -1;
279 #endif
280 D_OldMode = *Mode;
281 D_status_obuffree = -1;
282 Resize_obuf(); /* Allocate memory for buffer */
283 D_obufmax = defobuflimit;
284 D_obuflenmax = D_obuflen - D_obufmax;
285 #ifdef AUTO_NUKE
286 D_auto_nuke = defautonuke;
287 #endif
288 D_obufp = D_obuf;
289 D_printfd = -1;
290 D_userpid = pid;
292 #ifdef POSIX
293 if ((b = lookup_baud((int)cfgetospeed(&D_OldMode.tio))))
294 D_dospeed = b->idx;
295 #else
296 # ifdef TERMIO
297 if ((b = lookup_baud(D_OldMode.tio.c_cflag & CBAUD)))
298 D_dospeed = b->idx;
299 # else
300 D_dospeed = (short)D_OldMode.m_ttyb.sg_ospeed;
301 # endif
302 #endif
303 debug1("New displays ospeed = %d\n", D_dospeed);
305 strncpy(D_usertty, utty, sizeof(D_usertty) - 1);
306 D_usertty[sizeof(D_usertty) - 1] = 0;
307 strncpy(D_termname, term, sizeof(D_termname) - 1);
308 D_termname[sizeof(D_termname) - 1] = 0;
309 D_user = *u;
310 D_processinput = ProcessInput;
311 return display;
315 void
316 FreeDisplay()
318 struct win *p;
319 #ifdef MULTI
320 struct display *d, **dp;
321 #endif
323 #ifdef FONT
324 FreeTransTable();
325 #endif
326 #ifdef BLANKER_PRG
327 KillBlanker();
328 #endif
329 if (D_userfd >= 0)
331 Flush();
332 if (!display)
333 return;
334 SetTTY(D_userfd, &D_OldMode);
335 fcntl(D_userfd, F_SETFL, 0);
337 freetty();
338 if (D_tentry)
339 free(D_tentry);
340 D_tentry = 0;
341 if (D_processinputdata)
342 free(D_processinputdata);
343 D_processinputdata = 0;
344 D_tcinited = 0;
345 evdeq(&D_hstatusev);
346 evdeq(&D_statusev);
347 evdeq(&D_readev);
348 evdeq(&D_writeev);
349 evdeq(&D_blockedev);
350 #ifdef MAPKEYS
351 evdeq(&D_mapev);
352 if (D_kmaps)
354 free(D_kmaps);
355 D_kmaps = 0;
356 D_aseqs = 0;
357 D_nseqs = 0;
358 D_seqp = 0;
359 D_seql = 0;
360 D_seqh = 0;
362 #endif
363 evdeq(&D_idleev);
364 #ifdef BLANKER_PRG
365 evdeq(&D_blankerev);
366 #endif
367 #ifdef HAVE_BRAILLE
368 if (bd.bd_dpy == display)
370 bd.bd_start_braille = 0;
371 StartBraille();
373 #endif
375 #ifdef MULTI
376 for (dp = &displays; (d = *dp) ; dp = &d->d_next)
377 if (d == display)
378 break;
379 ASSERT(d);
380 if (D_status_lastmsg)
381 free(D_status_lastmsg);
382 if (D_obuf)
383 free(D_obuf);
384 *dp = display->d_next;
385 #else /* MULTI */
386 ASSERT(display == displays);
387 ASSERT(display == &TheDisplay);
388 displays = 0;
389 #endif /* MULTI */
391 while (D_canvas.c_slperp)
392 FreeCanvas(D_canvas.c_slperp);
393 D_cvlist = 0;
395 for (p = windows; p; p = p->w_next)
397 if (p->w_pdisplay == display)
398 p->w_pdisplay = 0;
399 if (p->w_lastdisp == display)
400 p->w_lastdisp = 0;
401 if (p->w_readev.condneg == &D_status || p->w_readev.condneg == &D_obuflenmax)
402 p->w_readev.condpos = p->w_readev.condneg = 0;
404 #ifdef ZMODEM
405 for (p = windows; p; p = p->w_next)
406 if (p->w_zdisplay == display)
407 zmodem_abort(p, 0);
408 #endif
409 #ifdef MULTI
410 free((char *)display);
411 #endif
412 display = 0;
416 MakeDefaultCanvas()
418 struct canvas *cv;
420 ASSERT(display);
421 if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
422 return -1;
423 cv->c_xs = 0;
424 cv->c_xe = D_width - 1;
425 cv->c_ys = 0;
426 cv->c_ye = D_height - 1 - (D_has_hstatus == HSTATUS_LASTLINE) - captionalways;
427 debug2("MakeDefaultCanvas 0,0 %d,%d\n", cv->c_xe, cv->c_ye);
428 cv->c_xoff = 0;
429 cv->c_yoff = 0;
430 cv->c_next = 0;
431 cv->c_display = display;
432 cv->c_vplist = 0;
433 cv->c_slnext = 0;
434 cv->c_slprev = 0;
435 cv->c_slperp = 0;
436 cv->c_slweight = 1;
437 cv->c_slback = &D_canvas;
438 D_canvas.c_slperp = cv;
439 D_canvas.c_xs = cv->c_xs;
440 D_canvas.c_xe = cv->c_xe;
441 D_canvas.c_ys = cv->c_ys;
442 D_canvas.c_ye = cv->c_ye;
443 cv->c_slorient = SLICE_UNKN;
444 cv->c_captev.type = EV_TIMEOUT;
445 cv->c_captev.data = (char *)cv;
446 cv->c_captev.handler = cv_winid_fn;
448 cv->c_blank.l_cvlist = cv;
449 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
450 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
451 cv->c_blank.l_x = cv->c_blank.l_y = 0;
452 cv->c_blank.l_layfn = &BlankLf;
453 cv->c_blank.l_data = 0;
454 cv->c_blank.l_next = 0;
455 cv->c_blank.l_bottom = &cv->c_blank;
456 cv->c_blank.l_blocking = 0;
457 cv->c_layer = &cv->c_blank;
458 cv->c_lnext = 0;
460 D_cvlist = cv;
461 RethinkDisplayViewports();
462 D_forecv = cv; /* default input focus */
463 return 0;
466 static struct canvas **
467 CreateCanvasChainRec(cv, cvp)
468 struct canvas *cv;
469 struct canvas **cvp;
471 for (; cv; cv = cv->c_slnext)
473 if (cv->c_slperp)
474 cvp = CreateCanvasChainRec(cv->c_slperp, cvp);
475 else
477 *cvp = cv;
478 cvp = &cv->c_next;
481 return cvp;
484 void
485 RecreateCanvasChain()
487 struct canvas **cvp;
488 cvp = CreateCanvasChainRec(D_canvas.c_slperp, &D_cvlist);
489 *cvp = 0;
492 static void
493 FreeCanvas(cv)
494 struct canvas *cv;
496 struct viewport *vp, *nvp;
497 struct canvas **cvp;
498 struct win *p;
500 if (cv->c_slprev)
501 cv->c_slprev->c_slnext = cv->c_slnext;
502 if (cv->c_slnext)
503 cv->c_slnext->c_slprev = cv->c_slprev;
504 if (cv->c_slback && cv->c_slback->c_slperp == cv)
505 cv->c_slback->c_slperp = cv->c_slnext ? cv->c_slnext : cv->c_slprev;
506 if (cv->c_slperp)
508 while (cv->c_slperp)
509 FreeCanvas(cv->c_slperp);
510 free(cv);
511 return;
514 if (display)
516 if (D_forecv == cv)
517 D_forecv = 0;
518 /* remove from canvas chain as SetCanvasWindow might call
519 * some layer function */
520 for (cvp = &D_cvlist; *cvp ; cvp = &(*cvp)->c_next)
521 if (*cvp == cv)
523 *cvp = cv->c_next;
524 break;
527 p = cv->c_layer ? Layer2Window(cv->c_layer) : 0;
528 SetCanvasWindow(cv, 0);
529 if (p)
530 WindowChanged(p, 'u');
531 if (flayer == cv->c_layer)
532 flayer = 0;
533 for (vp = cv->c_vplist; vp; vp = nvp)
535 vp->v_canvas = 0;
536 nvp = vp->v_next;
537 vp->v_next = 0;
538 free(vp);
540 evdeq(&cv->c_captev);
541 free(cv);
545 CountCanvas(cv)
546 struct canvas *cv;
548 int num = 0;
549 for (; cv; cv = cv->c_slnext)
551 if (cv->c_slperp)
553 struct canvas *cvp;
554 int nump = 1, n;
555 for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
556 if (cvp->c_slperp)
558 n = CountCanvas(cvp->c_slperp);
559 if (n > nump)
560 nump = n;
562 num += nump;
564 else
565 num++;
567 return num;
571 CountCanvasPerp(cv)
572 struct canvas *cv;
574 struct canvas *cvp;
575 int num = 1, n;
576 for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
577 if (cvp->c_slperp)
579 n = CountCanvas(cvp->c_slperp);
580 if (n > num)
581 num = n;
583 return num;
586 void
587 EqualizeCanvas(cv, gflag)
588 struct canvas *cv;
589 int gflag;
591 struct canvas *cv2;
592 for (; cv; cv = cv->c_slnext)
594 if (cv->c_slperp && gflag)
596 cv->c_slweight = CountCanvasPerp(cv);
597 for (cv2 = cv->c_slperp; cv2; cv2 = cv2->c_slnext)
598 if (cv2->c_slperp)
599 EqualizeCanvas(cv2->c_slperp, gflag);
601 else
602 cv->c_slweight = 1;
606 void
607 ResizeCanvas(cv)
608 struct canvas *cv;
610 struct canvas *cv2, *cvn, *fcv;
611 int nh, i, maxi, hh, m, w, wsum;
612 int need, got;
613 int xs, ys, xe, ye;
614 int focusmin = 0;
616 xs = cv->c_xs;
617 ys = cv->c_ys;
618 xe = cv->c_xe;
619 ye = cv->c_ye;
620 cv = cv->c_slperp;
621 debug2("ResizeCanvas: %d,%d", xs, ys);
622 debug2(" %d,%d\n", xe, ye);
623 if (cv == 0)
624 return;
625 if (cv->c_slorient == SLICE_UNKN)
627 ASSERT(!cv->c_slnext && !cv->c_slperp);
628 cv->c_xs = xs;
629 cv->c_xe = xe;
630 cv->c_ys = ys;
631 cv->c_ye = ye;
632 cv->c_xoff = cv->c_xs;
633 cv->c_yoff = cv->c_ys;
634 return;
637 fcv = 0;
638 if (focusminwidth || focusminheight)
640 debug("searching for focus canvas\n");
641 cv2 = D_forecv;
642 while (cv2->c_slback)
644 if (cv2->c_slback == cv->c_slback)
646 fcv = cv2;
647 focusmin = cv->c_slorient == SLICE_VERT ? focusminheight : focusminwidth;
648 if (focusmin > 0)
649 focusmin--;
650 else if (focusmin < 0)
651 focusmin = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
652 debug1("found, focusmin=%d\n", focusmin);
654 cv2 = cv2->c_slback;
657 if (focusmin)
659 m = CountCanvas(cv) * 2;
660 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
661 nh -= m;
662 if (nh < 0)
663 nh = 0;
664 if (focusmin > nh)
665 focusmin = nh;
666 debug1("corrected to %d\n", focusmin);
669 /* pass 1: calculate weight sum */
670 for (cv2 = cv, wsum = 0; cv2; cv2 = cv2->c_slnext)
672 debug1(" weight %d\n", cv2->c_slweight);
673 wsum += cv2->c_slweight;
675 debug1("wsum = %d\n", wsum);
676 if (wsum == 0)
677 wsum = 1;
678 w = wsum;
680 /* pass 2: calculate need/excess space */
681 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
682 for (cv2 = cv, need = got = 0; cv2; cv2 = cv2->c_slnext)
684 m = cv2->c_slperp ? CountCanvasPerp(cv2) * 2 - 1 : 1;
685 if (cv2 == fcv)
686 m += focusmin;
687 hh = cv2->c_slweight ? nh * cv2->c_slweight / w : 0;
688 w -= cv2->c_slweight;
689 nh -= hh;
690 debug2(" should %d min %d\n", hh, m);
691 if (hh <= m + 1)
692 need += m + 1 - hh;
693 else
694 got += hh - m - 1;
696 debug2("need: %d, got %d\n", need, got);
697 if (need > got)
698 need = got;
700 /* pass 3: distribute space */
701 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
702 i = cv->c_slorient == SLICE_VERT ? ys : xs;
703 maxi = cv->c_slorient == SLICE_VERT ? ye : xe;
704 w = wsum;
705 for (; cv; cv = cvn)
707 cvn = cv->c_slnext;
708 if (i > maxi)
710 if (cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slprev->c_slperp && !cv->c_slprev->c_slprev)
712 cv->c_slprev->c_slorient = SLICE_UNKN;
713 if (!captionalways)
715 cv->c_slback->c_ye++;
716 cv->c_slprev->c_ye++;
719 SetCanvasWindow(cv, 0);
720 FreeCanvas(cv);
721 continue;
723 m = cv->c_slperp ? CountCanvasPerp(cv) * 2 - 1 : 1;
724 if (cv == fcv)
725 m += focusmin;
726 hh = cv->c_slweight ? nh * cv->c_slweight / w : 0;
727 w -= cv->c_slweight;
728 nh -= hh;
729 debug2(" should %d min %d\n", hh, m);
730 if (hh <= m + 1)
732 hh = m + 1;
733 debug1(" -> %d\n", hh);
735 else
737 int hx = need * (hh - m - 1) / got;
738 debug3(" -> %d - %d = %d\n", hh, hx, hh - hx);
739 got -= (hh - m - 1);
740 hh -= hx;
741 need -= hx;
742 debug2(" now need=%d got=%d\n", need, got);
744 ASSERT(hh >= m + 1);
745 /* hh is window size plus pation line */
746 if (i + hh > maxi + 2)
748 hh = maxi + 2 - i;
749 debug1(" not enough space, reducing to %d\n", hh);
751 if (i + hh == maxi + 1)
753 hh++;
754 debug(" incrementing as no other canvas will fit\n");
756 if (cv->c_slorient == SLICE_VERT)
758 cv->c_xs = xs;
759 cv->c_xe = xe;
760 cv->c_ys = i;
761 cv->c_ye = i + hh - 2;
762 cv->c_xoff = xs;
763 cv->c_yoff = i;
765 else
767 cv->c_xs = i;
768 cv->c_xe = i + hh - 2;
769 cv->c_ys = ys;
770 cv->c_ye = ye;
771 cv->c_xoff = i;
772 cv->c_yoff = ys;
774 cv->c_xoff = cv->c_xs;
775 cv->c_yoff = cv->c_ys;
776 if (cv->c_slperp)
778 ResizeCanvas(cv);
779 if (!cv->c_slperp->c_slnext)
781 debug("deleting perp node\n");
782 FreePerp(cv->c_slperp);
783 FreePerp(cv);
786 i += hh;
790 static struct canvas *
791 AddPerp(cv)
792 struct canvas *cv;
794 struct canvas *pcv;
795 debug("Creating new perp node\n");
797 if ((pcv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
798 return 0;
799 pcv->c_next = 0;
800 pcv->c_display = cv->c_display;
801 pcv->c_slnext = cv->c_slnext;
802 pcv->c_slprev = cv->c_slprev;
803 pcv->c_slperp = cv;
804 pcv->c_slback = cv->c_slback;
805 if (cv->c_slback && cv->c_slback->c_slperp == cv)
806 cv->c_slback->c_slperp = pcv;
807 pcv->c_slorient = cv->c_slorient;
808 pcv->c_xoff = 0;
809 pcv->c_yoff = 0;
810 pcv->c_xs = cv->c_xs;
811 pcv->c_xe = cv->c_xe;
812 pcv->c_ys = cv->c_ys;
813 pcv->c_ye = cv->c_ye;
814 if (pcv->c_slnext)
815 pcv->c_slnext->c_slprev = pcv;
816 if (pcv->c_slprev)
817 pcv->c_slprev->c_slnext = pcv;
818 pcv->c_slweight = cv->c_slweight;
819 cv->c_slweight = 1;
820 cv->c_slnext = 0;
821 cv->c_slprev = 0;
822 cv->c_slperp = 0;
823 cv->c_slback = pcv;
824 cv->c_slorient = SLICE_UNKN;
825 return pcv;
828 static void
829 FreePerp(pcv)
830 struct canvas *pcv;
832 struct canvas *cv;
834 if (!pcv->c_slperp)
835 return;
836 cv = pcv->c_slperp;
837 cv->c_slprev = pcv->c_slprev;
838 if (cv->c_slprev)
839 cv->c_slprev->c_slnext = cv;
840 cv->c_slback = pcv->c_slback;
841 if (cv->c_slback && cv->c_slback->c_slperp == pcv)
842 cv->c_slback->c_slperp = cv;
843 cv->c_slorient = pcv->c_slorient;
844 cv->c_slweight = pcv->c_slweight;
845 while (cv->c_slnext)
847 cv = cv->c_slnext;
848 cv->c_slorient = pcv->c_slorient;
849 cv->c_slback = pcv->c_slback;
850 cv->c_slweight = pcv->c_slweight;
852 cv->c_slnext = pcv->c_slnext;
853 if (cv->c_slnext)
854 cv->c_slnext->c_slprev = cv;
855 free(pcv);
859 AddCanvas(orient)
860 int orient;
862 struct canvas *cv;
863 int xs, xe, ys, ye;
864 int h, num;
866 cv = D_forecv;
867 debug2("AddCanvas orient %d, forecv is %d\n", orient, cv->c_slorient);
869 if (cv->c_slorient != SLICE_UNKN && cv->c_slorient != orient)
870 if (!AddPerp(cv))
871 return -1;
873 cv = D_forecv;
874 xs = cv->c_slback->c_xs;
875 xe = cv->c_slback->c_xe;
876 ys = cv->c_slback->c_ys;
877 ye = cv->c_slback->c_ye;
878 if (!captionalways && cv == D_canvas.c_slperp && !cv->c_slnext)
879 ye--; /* need space for caption */
880 debug2("Adding Canvas to slice %d,%d ", xs, ys);
881 debug2("%d,%d\n", xe, ye);
883 num = CountCanvas(cv->c_slback->c_slperp) + 1;
884 debug1("Num = %d\n", num);
885 if (orient == SLICE_VERT)
886 h = ye - ys + 1;
887 else
888 h = xe - xs + 1;
890 h -= 2 * num - 1;
891 if (h < 0)
892 return -1; /* can't fit in */
894 if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
895 return -1;
897 D_forecv->c_slback->c_ye = ye; /* in case we modified it above */
898 D_forecv->c_slorient = orient; /* in case it was UNKN */
899 cv->c_slnext = D_forecv->c_slnext;
900 cv->c_slprev = D_forecv;
901 D_forecv->c_slnext = cv;
902 if (cv->c_slnext)
903 cv->c_slnext->c_slprev = cv;
904 cv->c_slorient = orient;
905 cv->c_slback = D_forecv->c_slback;
907 cv->c_xs = xs;
908 cv->c_xe = xe;
909 cv->c_ys = ys;
910 cv->c_ye = ye;
911 cv->c_xoff = 0;
912 cv->c_yoff = 0;
913 cv->c_display = display;
914 cv->c_vplist = 0;
915 cv->c_captev.type = EV_TIMEOUT;
916 cv->c_captev.data = (char *)cv;
917 cv->c_captev.handler = cv_winid_fn;
919 cv->c_blank.l_cvlist = cv;
920 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
921 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
922 cv->c_blank.l_x = cv->c_blank.l_y = 0;
923 cv->c_blank.l_layfn = &BlankLf;
924 cv->c_blank.l_data = 0;
925 cv->c_blank.l_next = 0;
926 cv->c_blank.l_bottom = &cv->c_blank;
927 cv->c_blank.l_blocking = 0;
928 cv->c_layer = &cv->c_blank;
929 cv->c_lnext = 0;
931 cv->c_next = 0;
933 cv = cv->c_slback;
934 EqualizeCanvas(cv->c_slperp, 0);
935 ResizeCanvas(cv);
936 RecreateCanvasChain();
937 RethinkDisplayViewports();
938 ResizeLayersToCanvases();
939 return 0;
942 void
943 RemCanvas()
945 int xs, xe, ys, ye;
946 struct canvas *cv;
948 debug("RemCanvas\n");
949 cv = D_forecv;
950 if (cv->c_slorient == SLICE_UNKN)
951 return;
952 while (cv->c_slprev)
953 cv = cv->c_slprev;
954 if (!cv->c_slnext)
955 return;
956 if (!cv->c_slnext->c_slnext && cv->c_slback->c_slback)
958 /* two canvases in slice, kill perp node */
959 cv = D_forecv;
960 debug("deleting perp node\n");
961 FreePerp(cv->c_slprev ? cv->c_slprev : cv->c_slnext);
962 FreePerp(cv->c_slback);
964 xs = cv->c_slback->c_xs;
965 xe = cv->c_slback->c_xe;
966 ys = cv->c_slback->c_ys;
967 ye = cv->c_slback->c_ye;
968 /* free canvas */
969 cv = D_forecv;
970 D_forecv = cv->c_slprev;
971 if (!D_forecv)
972 D_forecv = cv->c_slnext;
973 FreeCanvas(cv);
975 cv = D_forecv;
976 while (D_forecv->c_slperp)
977 D_forecv = D_forecv->c_slperp;
979 /* if only one canvas left, set orient back to unknown */
980 if (!cv->c_slnext && !cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slperp)
982 cv->c_slorient = SLICE_UNKN;
983 if (!captionalways)
984 cv->c_slback->c_ye = ++ye; /* caption line no longer needed */
986 cv = cv->c_slback;
987 EqualizeCanvas(cv->c_slperp, 0);
988 ResizeCanvas(cv);
990 D_fore = Layer2Window(D_forecv->c_layer);
991 flayer = D_forecv->c_layer;
993 RecreateCanvasChain();
994 RethinkDisplayViewports();
995 ResizeLayersToCanvases();
998 void
999 OneCanvas()
1001 struct canvas *cv = D_forecv, *ocv = 0;
1003 if (cv->c_slprev)
1005 ocv = cv->c_slprev;
1006 cv->c_slprev->c_slnext = cv->c_slnext;
1008 if (cv->c_slnext)
1010 ocv = cv->c_slnext;
1011 cv->c_slnext->c_slprev = cv->c_slprev;
1013 if (!ocv)
1014 return;
1015 if (cv->c_slback && cv->c_slback->c_slperp == cv)
1016 cv->c_slback->c_slperp = ocv;
1017 cv->c_slorient = SLICE_UNKN;
1018 while (D_canvas.c_slperp)
1019 FreeCanvas(D_canvas.c_slperp);
1020 cv = D_forecv;
1021 D_canvas.c_slperp = cv;
1022 cv->c_slback = &D_canvas;
1023 cv->c_slnext = 0;
1024 cv->c_slprev = 0;
1025 ASSERT(!cv->c_slperp);
1026 if (!captionalways)
1027 D_canvas.c_ye++; /* caption line no longer needed */
1028 ResizeCanvas(&D_canvas);
1029 RecreateCanvasChain();
1030 RethinkDisplayViewports();
1031 ResizeLayersToCanvases();
1035 RethinkDisplayViewports()
1037 struct canvas *cv;
1038 struct viewport *vp, *vpn;
1040 /* free old viewports */
1041 for (cv = display->d_cvlist; cv; cv = cv->c_next)
1043 for (vp = cv->c_vplist; vp; vp = vpn)
1045 vp->v_canvas = 0;
1046 vpn = vp->v_next;
1047 bzero((char *)vp, sizeof(*vp));
1048 free(vp);
1050 cv->c_vplist = 0;
1052 display->d_vpxmin = -1;
1053 display->d_vpxmax = -1;
1055 for (cv = display->d_cvlist; cv; cv = cv->c_next)
1057 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1058 return -1;
1059 #ifdef HOLE
1060 vp->v_canvas = cv;
1061 vp->v_xs = cv->c_xs;
1062 vp->v_ys = (cv->c_ys + cv->c_ye) / 2;
1063 vp->v_xe = cv->c_xe;
1064 vp->v_ye = cv->c_ye;
1065 vp->v_xoff = cv->c_xoff;
1066 vp->v_yoff = cv->c_yoff;
1067 vp->v_next = cv->c_vplist;
1068 cv->c_vplist = vp;
1070 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1071 return -1;
1072 vp->v_canvas = cv;
1073 vp->v_xs = (cv->c_xs + cv->c_xe) / 2;
1074 vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
1075 vp->v_xe = cv->c_xe;
1076 vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
1077 vp->v_xoff = cv->c_xoff;
1078 vp->v_yoff = cv->c_yoff;
1079 vp->v_next = cv->c_vplist;
1080 cv->c_vplist = vp;
1082 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1083 return -1;
1084 vp->v_canvas = cv;
1085 vp->v_xs = cv->c_xs;
1086 vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
1087 vp->v_xe = (3 * cv->c_xs + cv->c_xe) / 4 - 1;
1088 vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
1089 vp->v_xoff = cv->c_xoff;
1090 vp->v_yoff = cv->c_yoff;
1091 vp->v_next = cv->c_vplist;
1092 cv->c_vplist = vp;
1094 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1095 return -1;
1096 vp->v_canvas = cv;
1097 vp->v_xs = cv->c_xs;
1098 vp->v_ys = cv->c_ys;
1099 vp->v_xe = cv->c_xe;
1100 vp->v_ye = (3 * cv->c_ys + cv->c_ye) / 4 - 1;
1101 vp->v_xoff = cv->c_xoff;
1102 vp->v_yoff = cv->c_yoff;
1103 vp->v_next = cv->c_vplist;
1104 cv->c_vplist = vp;
1105 #else
1106 vp->v_canvas = cv;
1107 vp->v_xs = cv->c_xs;
1108 vp->v_ys = cv->c_ys;
1109 vp->v_xe = cv->c_xe;
1110 vp->v_ye = cv->c_ye;
1111 vp->v_xoff = cv->c_xoff;
1112 vp->v_yoff = cv->c_yoff;
1113 vp->v_next = cv->c_vplist;
1114 cv->c_vplist = vp;
1115 #endif
1117 if (cv->c_xs < display->d_vpxmin || display->d_vpxmin == -1)
1118 display->d_vpxmin = cv->c_xs;
1119 if (cv->c_xe > display->d_vpxmax || display->d_vpxmax == -1)
1120 display->d_vpxmax = cv->c_xe;
1122 return 0;
1125 void
1126 RethinkViewportOffsets(cv)
1127 struct canvas *cv;
1129 struct viewport *vp;
1131 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1133 vp->v_xoff = cv->c_xoff;
1134 vp->v_yoff = cv->c_yoff;
1139 * if the adaptflag is on, we keep the size of this display, else
1140 * we may try to restore our old window sizes.
1142 void
1143 InitTerm(adapt)
1144 int adapt;
1146 ASSERT(display);
1147 ASSERT(D_tcinited);
1148 D_top = D_bot = -1;
1149 AddCStr(D_TI);
1150 AddCStr(D_IS);
1151 /* Check for toggle */
1152 if (D_IM && strcmp(D_IM, D_EI))
1153 AddCStr(D_EI);
1154 D_insert = 0;
1155 #ifdef MAPKEYS
1156 AddCStr(D_KS);
1157 AddCStr(D_CCS);
1158 #else
1159 /* Check for toggle */
1160 if (D_KS && strcmp(D_KS, D_KE))
1161 AddCStr(D_KE);
1162 if (D_CCS && strcmp(D_CCS, D_CCE))
1163 AddCStr(D_CCE);
1164 #endif
1165 D_keypad = 0;
1166 D_cursorkeys = 0;
1167 AddCStr(D_ME);
1168 AddCStr(D_EA);
1169 AddCStr(D_CE0);
1170 D_rend = mchar_null;
1171 D_atyp = 0;
1172 if (adapt == 0)
1173 ResizeDisplay(D_defwidth, D_defheight);
1174 ChangeScrollRegion(0, D_height - 1);
1175 D_x = D_y = 0;
1176 Flush();
1177 ClearAll();
1178 debug1("we %swant to adapt all our windows to the display\n",
1179 (adapt) ? "" : "don't ");
1180 /* In case the size was changed by a init sequence */
1181 CheckScreenSize((adapt) ? 2 : 0);
1184 void
1185 FinitTerm()
1187 ASSERT(display);
1188 #ifdef BLANKER_PRG
1189 KillBlanker();
1190 #endif
1191 if (D_tcinited)
1193 ResizeDisplay(D_defwidth, D_defheight);
1194 InsertMode(0);
1195 ChangeScrollRegion(0, D_height - 1);
1196 KeypadMode(0);
1197 CursorkeysMode(0);
1198 CursorVisibility(0);
1199 MouseMode(0);
1200 SetRendition(&mchar_null);
1201 SetFlow(FLOW_NOW);
1202 #ifdef MAPKEYS
1203 AddCStr(D_KE);
1204 AddCStr(D_CCE);
1205 #endif
1206 if (D_hstatus)
1207 ShowHStatus((char *)0);
1208 #ifdef RXVT_OSC
1209 ClearAllXtermOSC();
1210 #endif
1211 D_x = D_y = -1;
1212 GotoPos(0, D_height - 1);
1213 AddChar('\r');
1214 AddChar('\n');
1215 AddCStr(D_TE);
1217 Flush();
1221 static void
1222 INSERTCHAR(c)
1223 int c;
1225 ASSERT(display);
1226 if (!D_insert && D_x < D_width - 1)
1228 if (D_IC || D_CIC)
1230 if (D_IC)
1231 AddCStr(D_IC);
1232 else
1233 AddCStr2(D_CIC, 1);
1234 RAW_PUTCHAR(c);
1235 return;
1237 InsertMode(1);
1238 if (!D_insert)
1240 RefreshLine(D_y, D_x, D_width-1, 0);
1241 return;
1244 RAW_PUTCHAR(c);
1247 void
1248 PUTCHAR(c)
1249 int c;
1251 ASSERT(display);
1252 if (D_insert && D_x < D_width - 1)
1253 InsertMode(0);
1254 RAW_PUTCHAR(c);
1257 void
1258 PUTCHARLP(c)
1259 int c;
1261 if (D_x < D_width - 1)
1263 if (D_insert)
1264 InsertMode(0);
1265 RAW_PUTCHAR(c);
1266 return;
1268 if (D_CLP || D_y != D_bot)
1270 int y = D_y;
1271 RAW_PUTCHAR(c);
1272 if (D_AM && !D_CLP)
1273 GotoPos(D_width - 1, y);
1274 return;
1276 debug("PUTCHARLP: lp_missing!\n");
1277 D_lp_missing = 1;
1278 D_rend.image = c;
1279 D_lpchar = D_rend;
1280 #ifdef DW_CHARS
1281 /* XXX -> PutChar ? */
1282 if (D_mbcs)
1284 D_lpchar.mbcs = c;
1285 D_lpchar.image = D_mbcs;
1286 D_mbcs = 0;
1287 D_x--;
1289 #endif
1293 * RAW_PUTCHAR() is for all text that will be displayed.
1294 * NOTE: charset Nr. 0 has a conversion table, but c1, c2, ... don't.
1297 STATIC void
1298 RAW_PUTCHAR(c)
1299 int c;
1301 ASSERT(display);
1303 #ifdef FONT
1304 # ifdef UTF8
1305 if (D_encoding == UTF8)
1307 c = (c & 255) | (unsigned char)D_rend.font << 8;
1308 # ifdef DW_CHARS
1309 if (D_mbcs)
1311 c = D_mbcs;
1312 if (D_x == D_width)
1313 D_x += D_AM ? 1 : -1;
1314 D_mbcs = 0;
1316 else if (utf8_isdouble(c))
1318 D_mbcs = c;
1319 D_x++;
1320 return;
1322 # endif
1323 if (c < 32)
1325 AddCStr2(D_CS0, '0');
1326 AddChar(c + 0x5f);
1327 AddCStr(D_CE0);
1328 goto addedutf8;
1330 AddUtf8(c);
1331 goto addedutf8;
1333 # endif
1334 # ifdef DW_CHARS
1335 if (is_dw_font(D_rend.font))
1337 int t = c;
1338 if (D_mbcs == 0)
1340 D_mbcs = c;
1341 D_x++;
1342 return;
1344 D_x--;
1345 if (D_x == D_width - 1)
1346 D_x += D_AM ? 1 : -1;
1347 c = D_mbcs;
1348 D_mbcs = t;
1350 # endif
1351 # if defined(ENCODINGS) && defined(DW_CHARS)
1352 if (D_encoding)
1353 c = PrepareEncodedChar(c);
1354 # endif
1355 # ifdef DW_CHARS
1356 kanjiloop:
1357 # endif
1358 if (D_xtable && D_xtable[(int)(unsigned char)D_rend.font] && D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c])
1359 AddStr(D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c]);
1360 else
1361 AddChar(D_rend.font != '0' ? c : D_c0_tab[(int)(unsigned char)c]);
1362 #else /* FONT */
1363 AddChar(c);
1364 #endif /* FONT */
1366 #ifdef UTF8
1367 addedutf8:
1368 #endif
1369 if (++D_x >= D_width)
1371 if (D_AM == 0)
1372 D_x = D_width - 1;
1373 else if (!D_CLP || D_x > D_width)
1375 D_x -= D_width;
1376 if (D_y < D_height-1 && D_y != D_bot)
1377 D_y++;
1380 #ifdef DW_CHARS
1381 if (D_mbcs)
1383 c = D_mbcs;
1384 D_mbcs = 0;
1385 goto kanjiloop;
1387 #endif
1390 static int
1391 DoAddChar(c)
1392 int c;
1394 /* this is for ESC-sequences only (AddChar is a macro) */
1395 AddChar(c);
1396 return c;
1399 void
1400 AddCStr(s)
1401 char *s;
1403 if (display && s && *s)
1405 ospeed = D_dospeed;
1406 tputs(s, 1, DoAddChar);
1410 void
1411 AddCStr2(s, c)
1412 char *s;
1413 int c;
1415 if (display && s && *s)
1417 ospeed = D_dospeed;
1418 tputs(tgoto(s, 0, c), 1, DoAddChar);
1423 /* Insert mode is a toggle on some terminals, so we need this hack:
1425 void
1426 InsertMode(on)
1427 int on;
1429 if (display && on != D_insert && D_IM)
1431 D_insert = on;
1432 if (on)
1433 AddCStr(D_IM);
1434 else
1435 AddCStr(D_EI);
1439 /* ...and maybe keypad application mode is a toggle, too:
1441 void
1442 KeypadMode(on)
1443 int on;
1445 #ifdef MAPKEYS
1446 if (display)
1447 D_keypad = on;
1448 #else
1449 if (display && D_keypad != on && D_KS)
1451 D_keypad = on;
1452 if (on)
1453 AddCStr(D_KS);
1454 else
1455 AddCStr(D_KE);
1457 #endif
1460 void
1461 CursorkeysMode(on)
1462 int on;
1464 #ifdef MAPKEYS
1465 if (display)
1466 D_cursorkeys = on;
1467 #else
1468 if (display && D_cursorkeys != on && D_CCS)
1470 D_cursorkeys = on;
1471 if (on)
1472 AddCStr(D_CCS);
1473 else
1474 AddCStr(D_CCE);
1476 #endif
1479 void
1480 ReverseVideo(on)
1481 int on;
1483 if (display && D_revvid != on && D_CVR)
1485 D_revvid = on;
1486 if (D_revvid)
1487 AddCStr(D_CVR);
1488 else
1489 AddCStr(D_CVN);
1493 void
1494 CursorVisibility(v)
1495 int v;
1497 if (display && D_curvis != v)
1499 if (D_curvis)
1500 AddCStr(D_VE); /* do this always, just to be safe */
1501 D_curvis = 0;
1502 if (v == -1 && D_VI)
1503 AddCStr(D_VI);
1504 else if (v == 1 && D_VS)
1505 AddCStr(D_VS);
1506 else
1507 return;
1508 D_curvis = v;
1512 void
1513 MouseMode(mode)
1514 int mode;
1516 if (display && D_mouse != mode)
1518 char mousebuf[20];
1519 if (!D_CXT)
1520 return;
1521 if (D_mouse)
1523 sprintf(mousebuf, "\033[?%dl", D_mouse);
1524 AddStr(mousebuf);
1526 if (mode)
1528 sprintf(mousebuf, "\033[?%dh", mode);
1529 AddStr(mousebuf);
1531 D_mouse = mode;
1535 static int StrCost;
1537 /* ARGSUSED */
1538 static int
1539 CountChars(c)
1540 int c;
1542 StrCost++;
1543 return c;
1547 CalcCost(s)
1548 register char *s;
1550 ASSERT(display);
1551 if (s)
1553 StrCost = 0;
1554 ospeed = D_dospeed;
1555 tputs(s, 1, CountChars);
1556 return StrCost;
1558 else
1559 return EXPENSIVE;
1562 static int
1563 CallRewrite(y, xs, xe, doit)
1564 int y, xs, xe, doit;
1566 struct canvas *cv, *cvlist, *cvlnext;
1567 struct viewport *vp;
1568 struct layer *oldflayer;
1569 int cost;
1571 debug3("CallRewrite %d %d %d\n", y, xs, xe);
1572 ASSERT(display);
1573 ASSERT(xe >= xs);
1575 vp = 0;
1576 for (cv = D_cvlist; cv; cv = cv->c_next)
1578 if (y < cv->c_ys || y > cv->c_ye || xe < cv->c_xs || xs > cv->c_xe)
1579 continue;
1580 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1581 if (y >= vp->v_ys && y <= vp->v_ye && xe >= vp->v_xs && xs <= vp->v_xe)
1582 break;
1583 if (vp)
1584 break;
1586 if (doit)
1588 oldflayer = flayer;
1589 flayer = cv->c_layer;
1590 cvlist = flayer->l_cvlist;
1591 cvlnext = cv->c_lnext;
1592 flayer->l_cvlist = cv;
1593 cv->c_lnext = 0;
1594 LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 1);
1595 flayer->l_cvlist = cvlist;
1596 cv->c_lnext = cvlnext;
1597 flayer = oldflayer;
1598 return 0;
1600 if (cv == 0 || cv->c_layer == 0)
1601 return EXPENSIVE; /* not found or nothing on it */
1602 if (xs < vp->v_xs || xe > vp->v_xe)
1603 return EXPENSIVE; /* crosses viewport boundaries */
1604 if (y - vp->v_yoff < 0 || y - vp->v_yoff >= cv->c_layer->l_height)
1605 return EXPENSIVE; /* line not on layer */
1606 if (xs - vp->v_xoff < 0 || xe - vp->v_xoff >= cv->c_layer->l_width)
1607 return EXPENSIVE; /* line not on layer */
1608 #ifdef UTF8
1609 if (D_encoding == UTF8)
1610 D_rend.font = 0;
1611 #endif
1612 oldflayer = flayer;
1613 flayer = cv->c_layer;
1614 debug3("Calling Rewrite %d %d %d\n", y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff);
1615 cost = LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 0);
1616 flayer = oldflayer;
1617 if (D_insert)
1618 cost += D_EIcost + D_IMcost;
1619 return cost;
1623 void
1624 GotoPos(x2, y2)
1625 int x2, y2;
1627 register int dy, dx, x1, y1;
1628 register int costx, costy;
1629 register int m;
1630 register char *s;
1631 int CMcost;
1632 enum move_t xm = M_NONE, ym = M_NONE;
1634 if (!display)
1635 return;
1637 x1 = D_x;
1638 y1 = D_y;
1640 if (x1 == D_width)
1642 if (D_CLP && D_AM)
1643 x1 = -1; /* don't know how the terminal treats this */
1644 else
1645 x1--;
1647 if (x2 == D_width)
1648 x2--;
1649 dx = x2 - x1;
1650 dy = y2 - y1;
1651 if (dy == 0 && dx == 0)
1652 return;
1653 debug2("GotoPos (%d,%d)", x1, y1);
1654 debug2(" -> (%d,%d)\n", x2, y2);
1655 if (!D_MS) /* Safe to move ? */
1656 SetRendition(&mchar_null);
1657 if (y1 < 0 /* don't know the y position */
1658 || (y2 > D_bot && y1 <= D_bot) /* have to cross border */
1659 || (y2 < D_top && y1 >= D_top)) /* of scrollregion ? */
1661 DoCM:
1662 if (D_HO && !x2 && !y2)
1663 AddCStr(D_HO);
1664 else
1665 AddCStr(tgoto(D_CM, x2, y2));
1666 D_x = x2;
1667 D_y = y2;
1668 return;
1671 /* some scrollregion implementations don't allow movements
1672 * away from the region. sigh.
1674 if ((y1 > D_bot && y2 > y1) || (y1 < D_top && y2 < y1))
1675 goto DoCM;
1677 /* Calculate CMcost */
1678 if (D_HO && !x2 && !y2)
1679 s = D_HO;
1680 else
1681 s = tgoto(D_CM, x2, y2);
1682 CMcost = CalcCost(s);
1684 /* Calculate the cost to move the cursor to the right x position */
1685 costx = EXPENSIVE;
1686 if (x1 >= 0) /* relativ x positioning only if we know where we are */
1688 if (dx > 0)
1690 if (D_CRI && (dx > 1 || !D_ND))
1692 costx = CalcCost(tgoto(D_CRI, 0, dx));
1693 xm = M_CRI;
1695 if ((m = D_NDcost * dx) < costx)
1697 costx = m;
1698 xm = M_RI;
1700 /* Speedup: dx <= LayRewrite() */
1701 if (dx < costx && (m = CallRewrite(y1, x1, x2 - 1, 0)) < costx)
1703 costx = m;
1704 xm = M_RW;
1707 else if (dx < 0)
1709 if (D_CLE && (dx < -1 || !D_BC))
1711 costx = CalcCost(tgoto(D_CLE, 0, -dx));
1712 xm = M_CLE;
1714 if ((m = -dx * D_LEcost) < costx)
1716 costx = m;
1717 xm = M_LE;
1720 else
1721 costx = 0;
1723 /* Speedup: LayRewrite() >= x2 */
1724 if (x2 + D_CRcost < costx && (m = (x2 ? CallRewrite(y1, 0, x2 - 1, 0) : 0) + D_CRcost) < costx)
1726 costx = m;
1727 xm = M_CR;
1730 /* Check if it is already cheaper to do CM */
1731 if (costx >= CMcost)
1732 goto DoCM;
1734 /* Calculate the cost to move the cursor to the right y position */
1735 costy = EXPENSIVE;
1736 if (dy > 0)
1738 if (D_CDO && dy > 1) /* DO & NL are always != 0 */
1740 costy = CalcCost(tgoto(D_CDO, 0, dy));
1741 ym = M_CDO;
1743 if ((m = dy * ((x2 == 0) ? D_NLcost : D_DOcost)) < costy)
1745 costy = m;
1746 ym = M_DO;
1749 else if (dy < 0)
1751 if (D_CUP && (dy < -1 || !D_UP))
1753 costy = CalcCost(tgoto(D_CUP, 0, -dy));
1754 ym = M_CUP;
1756 if ((m = -dy * D_UPcost) < costy)
1758 costy = m;
1759 ym = M_UP;
1762 else
1763 costy = 0;
1765 /* Finally check if it is cheaper to do CM */
1766 if (costx + costy >= CMcost)
1767 goto DoCM;
1769 switch (xm)
1771 case M_LE:
1772 while (dx++ < 0)
1773 AddCStr(D_BC);
1774 break;
1775 case M_CLE:
1776 AddCStr2(D_CLE, -dx);
1777 break;
1778 case M_RI:
1779 while (dx-- > 0)
1780 AddCStr(D_ND);
1781 break;
1782 case M_CRI:
1783 AddCStr2(D_CRI, dx);
1784 break;
1785 case M_CR:
1786 AddCStr(D_CR);
1787 D_x = 0;
1788 x1 = 0;
1789 /* FALLTHROUGH */
1790 case M_RW:
1791 if (x1 < x2)
1792 (void) CallRewrite(y1, x1, x2 - 1, 1);
1793 break;
1794 default:
1795 break;
1798 switch (ym)
1800 case M_UP:
1801 while (dy++ < 0)
1802 AddCStr(D_UP);
1803 break;
1804 case M_CUP:
1805 AddCStr2(D_CUP, -dy);
1806 break;
1807 case M_DO:
1808 s = (x2 == 0) ? D_NL : D_DO;
1809 while (dy-- > 0)
1810 AddCStr(s);
1811 break;
1812 case M_CDO:
1813 AddCStr2(D_CDO, dy);
1814 break;
1815 default:
1816 break;
1818 D_x = x2;
1819 D_y = y2;
1822 void
1823 ClearAll()
1825 ASSERT(display);
1826 ClearArea(0, 0, 0, D_width - 1, D_width - 1, D_height - 1, 0, 0);
1829 void
1830 ClearArea(x1, y1, xs, xe, x2, y2, bce, uselayfn)
1831 int x1, y1, xs, xe, x2, y2, bce, uselayfn;
1833 int y, xxe;
1834 struct canvas *cv;
1835 struct viewport *vp;
1837 debug2("Clear %d,%d", x1, y1);
1838 debug2(" %d-%d", xs, xe);
1839 debug2(" %d,%d", x2, y2);
1840 debug2(" uselayfn=%d bce=%d\n", uselayfn, bce);
1841 ASSERT(display);
1842 if (x1 == D_width)
1843 x1--;
1844 if (x2 == D_width)
1845 x2--;
1846 if (xs == -1)
1847 xs = x1;
1848 if (xe == -1)
1849 xe = x2;
1850 if (D_UT) /* Safe to erase ? */
1851 SetRendition(&mchar_null);
1852 #ifdef COLOR
1853 if (D_BE)
1854 SetBackColor(bce);
1855 #endif
1856 if (D_lp_missing && y1 <= D_bot && xe >= D_width - 1)
1858 if (y2 > D_bot || (y2 == D_bot && x2 >= D_width - 1))
1859 D_lp_missing = 0;
1861 if (x2 == D_width - 1 && (xs == 0 || y1 == y2) && xe == D_width - 1 && y2 == D_height - 1 && (!bce || D_BE))
1863 #ifdef AUTO_NUKE
1864 if (x1 == 0 && y1 == 0 && D_auto_nuke)
1865 NukePending();
1866 #endif
1867 if (x1 == 0 && y1 == 0 && D_CL)
1869 AddCStr(D_CL);
1870 D_y = D_x = 0;
1871 return;
1874 * Workaround a hp700/22 terminal bug. Do not use CD where CE
1875 * is also appropriate.
1877 if (D_CD && (y1 < y2 || !D_CE))
1879 GotoPos(x1, y1);
1880 AddCStr(D_CD);
1881 return;
1884 if (x1 == 0 && xs == 0 && (xe == D_width - 1 || y1 == y2) && y1 == 0 && D_CCD && (!bce || D_BE))
1886 GotoPos(x1, y1);
1887 AddCStr(D_CCD);
1888 return;
1890 xxe = xe;
1891 for (y = y1; y <= y2; y++, x1 = xs)
1893 if (y == y2)
1894 xxe = x2;
1895 if (x1 == 0 && D_CB && (xxe != D_width - 1 || (D_x == xxe && D_y == y)) && (!bce || D_BE))
1897 GotoPos(xxe, y);
1898 AddCStr(D_CB);
1899 continue;
1901 if (xxe == D_width - 1 && D_CE && (!bce || D_BE))
1903 GotoPos(x1, y);
1904 AddCStr(D_CE);
1905 continue;
1907 if (uselayfn)
1909 vp = 0;
1910 for (cv = D_cvlist; cv; cv = cv->c_next)
1912 if (y < cv->c_ys || y > cv->c_ye || xxe < cv->c_xs || x1 > cv->c_xe)
1913 continue;
1914 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1915 if (y >= vp->v_ys && y <= vp->v_ye && xxe >= vp->v_xs && x1 <= vp->v_xe)
1916 break;
1917 if (vp)
1918 break;
1920 if (cv && cv->c_layer && x1 >= vp->v_xs && xxe <= vp->v_xe &&
1921 y - vp->v_yoff >= 0 && y - vp->v_yoff < cv->c_layer->l_height &&
1922 xxe - vp->v_xoff >= 0 && x1 - vp->v_xoff < cv->c_layer->l_width)
1924 struct layer *oldflayer = flayer;
1925 struct canvas *cvlist, *cvlnext;
1926 flayer = cv->c_layer;
1927 cvlist = flayer->l_cvlist;
1928 cvlnext = cv->c_lnext;
1929 flayer->l_cvlist = cv;
1930 cv->c_lnext = 0;
1931 LayClearLine(y - vp->v_yoff, x1 - vp->v_xoff, xxe - vp->v_xoff, bce);
1932 flayer->l_cvlist = cvlist;
1933 cv->c_lnext = cvlnext;
1934 flayer = oldflayer;
1935 continue;
1938 ClearLine((struct mline *)0, y, x1, xxe, bce);
1944 * if cur_only > 0, we only redisplay current line, as a full refresh is
1945 * too expensive over a low baud line.
1947 void
1948 Redisplay(cur_only)
1949 int cur_only;
1951 ASSERT(display);
1953 /* XXX do em all? */
1954 InsertMode(0);
1955 ChangeScrollRegion(0, D_height - 1);
1956 KeypadMode(0);
1957 CursorkeysMode(0);
1958 CursorVisibility(0);
1959 MouseMode(0);
1960 SetRendition(&mchar_null);
1961 SetFlow(FLOW_NOW);
1963 ClearAll();
1964 #ifdef RXVT_OSC
1965 RefreshXtermOSC();
1966 #endif
1967 if (cur_only > 0 && D_fore)
1968 RefreshArea(0, D_fore->w_y, D_width - 1, D_fore->w_y, 1);
1969 else
1970 RefreshAll(1);
1971 RefreshHStatus();
1972 CV_CALL(D_forecv, LayRestore();LaySetCursor());
1975 void
1976 RedisplayDisplays(cur_only)
1977 int cur_only;
1979 struct display *olddisplay = display;
1980 for (display = displays; display; display = display->d_next)
1981 Redisplay(cur_only);
1982 display = olddisplay;
1986 /* XXX: use oml! */
1987 void
1988 ScrollH(y, xs, xe, n, bce, oml)
1989 int y, xs, xe, n, bce;
1990 struct mline *oml;
1992 int i;
1994 if (n == 0)
1995 return;
1996 if (xe != D_width - 1)
1998 RefreshLine(y, xs, xe, 0);
1999 /* UpdateLine(oml, y, xs, xe); */
2000 return;
2002 GotoPos(xs, y);
2003 if (D_UT)
2004 SetRendition(&mchar_null);
2005 #ifdef COLOR
2006 if (D_BE)
2007 SetBackColor(bce);
2008 #endif
2009 if (n > 0)
2011 if (n >= xe - xs + 1)
2012 n = xe - xs + 1;
2013 if (D_CDC && !(n == 1 && D_DC))
2014 AddCStr2(D_CDC, n);
2015 else if (D_DC)
2017 for (i = n; i--; )
2018 AddCStr(D_DC);
2020 else
2022 RefreshLine(y, xs, xe, 0);
2023 /* UpdateLine(oml, y, xs, xe); */
2024 return;
2027 else
2029 if (-n >= xe - xs + 1)
2030 n = -(xe - xs + 1);
2031 if (!D_insert)
2033 if (D_CIC && !(n == -1 && D_IC))
2034 AddCStr2(D_CIC, -n);
2035 else if (D_IC)
2037 for (i = -n; i--; )
2038 AddCStr(D_IC);
2040 else if (D_IM)
2042 InsertMode(1);
2043 SetRendition(&mchar_null);
2044 #ifdef COLOR
2045 SetBackColor(bce);
2046 #endif
2047 for (i = -n; i--; )
2048 INSERTCHAR(' ');
2049 bce = 0; /* all done */
2051 else
2053 /* UpdateLine(oml, y, xs, xe); */
2054 RefreshLine(y, xs, xe, 0);
2055 return;
2058 else
2060 SetRendition(&mchar_null);
2061 #ifdef COLOR
2062 SetBackColor(bce);
2063 #endif
2064 for (i = -n; i--; )
2065 INSERTCHAR(' ');
2066 bce = 0; /* all done */
2069 if (bce && !D_BE)
2071 if (n > 0)
2072 ClearLine((struct mline *)0, y, xe - n + 1, xe, bce);
2073 else
2074 ClearLine((struct mline *)0, y, xs, xs - n - 1, bce);
2076 if (D_lp_missing && y == D_bot)
2078 if (n > 0)
2079 WriteLP(D_width - 1 - n, y);
2080 D_lp_missing = 0;
2084 void
2085 ScrollV(xs, ys, xe, ye, n, bce)
2086 int xs, ys, xe, ye, n, bce;
2088 int i;
2089 int up;
2090 int oldtop, oldbot;
2091 int alok, dlok, aldlfaster;
2092 int missy = 0;
2094 ASSERT(display);
2095 if (n == 0)
2096 return;
2097 if (n >= ye - ys + 1 || -n >= ye - ys + 1)
2099 ClearArea(xs, ys, xs, xe, xe, ye, bce, 0);
2100 return;
2102 if (xs > D_vpxmin || xe < D_vpxmax)
2104 RefreshArea(xs, ys, xe, ye, 0);
2105 return;
2108 if (D_lp_missing)
2110 if (D_bot > ye || D_bot < ys)
2111 missy = D_bot;
2112 else
2114 missy = D_bot - n;
2115 if (missy > ye || missy < ys)
2116 D_lp_missing = 0;
2120 up = 1;
2121 if (n < 0)
2123 up = 0;
2124 n = -n;
2126 if (n >= ye - ys + 1)
2127 n = ye - ys + 1;
2129 oldtop = D_top;
2130 oldbot = D_bot;
2131 if (ys < D_top || D_bot != ye)
2132 ChangeScrollRegion(ys, ye);
2133 alok = (D_AL || D_CAL || (ys >= D_top && ye == D_bot && up));
2134 dlok = (D_DL || D_CDL || (ys >= D_top && ye == D_bot && !up));
2135 if (D_top != ys && !(alok && dlok))
2136 ChangeScrollRegion(ys, ye);
2138 if (D_lp_missing &&
2139 (oldbot != D_bot ||
2140 (oldbot == D_bot && up && D_top == ys && D_bot == ye)))
2142 WriteLP(D_width - 1, oldbot);
2143 if (oldbot == D_bot) /* have scrolled */
2145 if (--n == 0)
2147 /* XXX
2148 ChangeScrollRegion(oldtop, oldbot);
2150 if (bce && !D_BE)
2151 ClearLine((struct mline *)0, ye, xs, xe, bce);
2152 return;
2157 if (D_UT)
2158 SetRendition(&mchar_null);
2159 #ifdef COLOR
2160 if (D_BE)
2161 SetBackColor(bce);
2162 #endif
2164 aldlfaster = (n > 1 && ys >= D_top && ye == D_bot && ((up && D_CDL) || (!up && D_CAL)));
2166 if ((up || D_SR) && D_top == ys && D_bot == ye && !aldlfaster)
2168 if (up)
2170 GotoPos(0, ye);
2171 for(i = n; i-- > 0; )
2172 AddCStr(D_NL); /* was SF, I think NL is faster */
2174 else
2176 GotoPos(0, ys);
2177 for(i = n; i-- > 0; )
2178 AddCStr(D_SR);
2181 else if (alok && dlok)
2183 if (up || ye != D_bot)
2185 GotoPos(0, up ? ys : ye+1-n);
2186 if (D_CDL && !(n == 1 && D_DL))
2187 AddCStr2(D_CDL, n);
2188 else
2189 for(i = n; i--; )
2190 AddCStr(D_DL);
2192 if (!up || ye != D_bot)
2194 GotoPos(0, up ? ye+1-n : ys);
2195 if (D_CAL && !(n == 1 && D_AL))
2196 AddCStr2(D_CAL, n);
2197 else
2198 for(i = n; i--; )
2199 AddCStr(D_AL);
2202 else
2204 RefreshArea(xs, ys, xe, ye, 0);
2205 return;
2207 if (bce && !D_BE)
2209 if (up)
2210 ClearArea(xs, ye - n + 1, xs, xe, xe, ye, bce, 0);
2211 else
2212 ClearArea(xs, ys, xs, xe, xe, ys + n - 1, bce, 0);
2214 if (D_lp_missing && missy != D_bot)
2215 WriteLP(D_width - 1, missy);
2216 /* XXX
2217 ChangeScrollRegion(oldtop, oldbot);
2218 if (D_lp_missing && missy != D_bot)
2219 WriteLP(D_width - 1, missy);
2223 void
2224 SetAttr(new)
2225 register int new;
2227 register int i, j, old, typ;
2229 if (!display || (old = D_rend.attr) == new)
2230 return;
2231 #ifdef COLORS16
2232 D_col16change = (old ^ new) & (A_BFG | A_BBG);
2233 new ^= D_col16change;
2234 if (old == new)
2235 return;
2236 #endif
2237 #if defined(TERMINFO) && defined(USE_SGR)
2238 if (D_SA)
2240 char *tparm();
2241 SetFont(ASCII);
2242 ospeed = D_dospeed;
2243 tputs(tparm(D_SA, new & A_SO, new & A_US, new & A_RV, new & A_BL,
2244 new & A_DI, new & A_BD, 0 , 0 ,
2245 0), 1, DoAddChar);
2246 D_rend.attr = new;
2247 D_atyp = 0;
2248 # ifdef COLOR
2249 if (D_hascolor)
2250 rend_setdefault(&D_rend);
2251 # endif
2252 return;
2254 #endif
2255 D_rend.attr = new;
2256 typ = D_atyp;
2257 if ((new & old) != old)
2259 if ((typ & ATYP_U))
2260 AddCStr(D_UE);
2261 if ((typ & ATYP_S))
2262 AddCStr(D_SE);
2263 if ((typ & ATYP_M))
2265 AddCStr(D_ME);
2266 #ifdef COLOR
2267 /* ansi attrib handling: \E[m resets color, too */
2268 if (D_hascolor)
2269 rend_setdefault(&D_rend);
2270 #endif
2271 #ifdef FONT
2272 if (!D_CG0)
2274 /* D_ME may also reset the alternate charset */
2275 D_rend.font = 0;
2276 # ifdef ENCODINGS
2277 D_realfont = 0;
2278 # endif
2280 #endif
2282 old = 0;
2283 typ = 0;
2285 old ^= new;
2286 for (i = 0, j = 1; old && i < NATTR; i++, j <<= 1)
2288 if ((old & j) == 0)
2289 continue;
2290 old ^= j;
2291 if (D_attrtab[i])
2293 AddCStr(D_attrtab[i]);
2294 typ |= D_attrtyp[i];
2297 D_atyp = typ;
2300 #ifdef FONT
2301 void
2302 SetFont(new)
2303 int new;
2305 int old = D_rend.font;
2306 if (!display || old == new)
2307 return;
2308 D_rend.font = new;
2309 #ifdef ENCODINGS
2310 if (D_encoding && CanEncodeFont(D_encoding, new))
2311 return;
2312 if (new == D_realfont)
2313 return;
2314 D_realfont = new;
2315 #endif
2316 if (D_xtable && D_xtable[(int)(unsigned char)new] &&
2317 D_xtable[(int)(unsigned char)new][256])
2319 AddCStr(D_xtable[(int)(unsigned char)new][256]);
2320 return;
2323 if (!D_CG0 && new != '0')
2325 new = ASCII;
2326 if (old == new)
2327 return;
2330 if (new == ASCII)
2331 AddCStr(D_CE0);
2332 #ifdef DW_CHARS
2333 else if (new < ' ')
2335 AddStr("\033$");
2336 if (new > 2)
2337 AddChar('(');
2338 AddChar(new + '@');
2340 #endif
2341 else
2342 AddCStr2(D_CS0, new);
2344 #endif
2346 #ifdef COLOR
2349 color256to16(jj)
2350 int jj;
2352 int min, max;
2353 int r, g, b;
2355 if (jj >= 232)
2357 jj = (jj - 232) / 6;
2358 jj = (jj & 1) << 3 | (jj & 2 ? 7 : 0);
2360 else if (jj >= 16)
2362 jj -= 16;
2363 r = jj / 36;
2364 g = (jj / 6) % 6;
2365 b = jj % 6;
2366 min = r < g ? (r < b ? r : b) : (g < b ? g : b);
2367 max = r > g ? (r > b ? r : b) : (g > b ? g : b);
2368 if (min == max)
2369 jj = ((max + 1) & 2) << 2 | ((max + 1) & 4 ? 7 : 0);
2370 else
2371 jj = (b - min) / (max - min) << 2 | (g - min) / (max - min) << 1 | (r -
2372 min) / (max - min) | (max > 3 ? 8 : 0);
2374 return jj;
2377 #ifdef COLORS256
2379 color256to88(jj)
2380 int jj;
2382 int r, g, b;
2384 if (jj >= 232)
2385 return (jj - 232) / 3 + 80;
2386 if (jj >= 16)
2388 jj -= 16;
2389 r = jj / 36;
2390 g = (jj / 6) % 6;
2391 b = jj % 6;
2392 return ((r + 1) / 2) * 16 + ((g + 1) / 2) * 4 + ((b + 1) / 2) + 16;
2394 return jj;
2396 #endif
2398 void
2399 SetColor(f, b)
2400 int f, b;
2402 int of, ob;
2403 static unsigned char sftrans[8] = {0,4,2,6,1,5,3,7};
2405 if (!display)
2406 return;
2408 of = rend_getfg(&D_rend);
2409 ob = rend_getbg(&D_rend);
2411 #ifdef COLORS16
2412 /* intense default not invented yet */
2413 if (f == 0x100)
2414 f = 0;
2415 if (b == 0x100)
2416 b = 0;
2417 #endif
2418 debug2("SetColor %d %d", coli2e(of), coli2e(ob));
2419 debug2(" -> %d %d\n", coli2e(f), coli2e(b));
2420 debug2("(%d %d", of, ob);
2421 debug2(" -> %d %d)\n", f, b);
2423 if (!D_CAX && D_hascolor && ((f == 0 && f != of) || (b == 0 && b != ob)))
2425 if (D_OP)
2426 AddCStr(D_OP);
2427 else
2429 int oattr;
2430 oattr = D_rend.attr;
2431 AddCStr(D_ME ? D_ME : "\033[m");
2432 #ifdef FONT
2433 if (D_ME && !D_CG0)
2435 /* D_ME may also reset the alternate charset */
2436 D_rend.font = 0;
2437 # ifdef ENCODINGS
2438 D_realfont = 0;
2439 # endif
2441 #endif
2442 D_atyp = 0;
2443 D_rend.attr = 0;
2444 SetAttr(oattr);
2446 of = ob = 0;
2448 rend_setfg(&D_rend, f);
2449 rend_setbg(&D_rend, b);
2450 #ifdef COLORS16
2451 D_col16change = 0;
2452 #endif
2453 if (!D_hascolor)
2454 return;
2455 f = f ? coli2e(f) : -1;
2456 b = b ? coli2e(b) : -1;
2457 of = of ? coli2e(of) : -1;
2458 ob = ob ? coli2e(ob) : -1;
2459 #ifdef COLORS256
2460 if (f != of && f > 15 && D_CCO != 256)
2461 f = D_CCO == 88 && D_CAF ? color256to88(f) : color256to16(f);
2462 if (f != of && f > 15 && D_CAF)
2464 AddCStr2(D_CAF, f);
2465 of = f;
2467 if (b != ob && b > 15 && D_CCO != 256)
2468 b = D_CCO == 88 && D_CAB ? color256to88(b) : color256to16(b);
2469 if (b != ob && b > 15 && D_CAB)
2471 AddCStr2(D_CAB, b);
2472 ob = b;
2474 #endif
2475 if (f != of && f != (of | 8))
2477 if (f == -1)
2478 AddCStr("\033[39m"); /* works because AX is set */
2479 else if (D_CAF)
2480 AddCStr2(D_CAF, f & 7);
2481 else if (D_CSF)
2482 AddCStr2(D_CSF, sftrans[f & 7]);
2484 if (b != ob && b != (ob | 8))
2486 if (b == -1)
2487 AddCStr("\033[49m"); /* works because AX is set */
2488 else if (D_CAB)
2489 AddCStr2(D_CAB, b & 7);
2490 else if (D_CSB)
2491 AddCStr2(D_CSB, sftrans[b & 7]);
2493 #ifdef COLORS16
2494 if (f != of && D_CXT && (f & 8) != 0 && f != -1)
2496 # ifdef TERMINFO
2497 AddCStr2("\033[9%p1%dm", f & 7);
2498 # else
2499 AddCStr2("\033[9%dm", f & 7);
2500 # endif
2502 if (b != ob && D_CXT && (b & 8) != 0 && b != -1)
2504 # ifdef TERMINFO
2505 AddCStr2("\033[10%p1%dm", b & 7);
2506 # else
2507 AddCStr2("\033[10%dm", b & 7);
2508 # endif
2510 #endif
2513 static void
2514 SetBackColor(new)
2515 int new;
2517 if (!display)
2518 return;
2519 SetColor(rend_getfg(&D_rend), new);
2521 #endif /* COLOR */
2523 void
2524 SetRendition(mc)
2525 struct mchar *mc;
2527 if (!display)
2528 return;
2529 if (nattr2color && D_hascolor && (mc->attr & nattr2color) != 0)
2531 static struct mchar mmc;
2532 int i;
2533 mmc = *mc;
2534 for (i = 0; i < 8; i++)
2535 if (attr2color[i] && (mc->attr & (1 << i)) != 0)
2537 if (mc->color == 0 && attr2color[i][3])
2538 ApplyAttrColor(attr2color[i][3], &mmc);
2539 else if ((mc->color & 0x0f) == 0 && attr2color[i][2])
2540 ApplyAttrColor(attr2color[i][2], &mmc);
2541 else if ((mc->color & 0xf0) == 0 && attr2color[i][1])
2542 ApplyAttrColor(attr2color[i][1], &mmc);
2543 else
2544 ApplyAttrColor(attr2color[i][0], &mmc);
2546 mc = &mmc;
2547 debug2("SetRendition: mapped to %02x %02x\n", (unsigned char)mc->attr, 0x99 - (unsigned char)mc->color);
2549 if (D_hascolor && D_CC8 && (mc->attr & (A_BFG|A_BBG)))
2551 int a = mc->attr;
2552 if ((mc->attr & A_BFG) && D_MD)
2553 a |= A_BD;
2554 if ((mc->attr & A_BBG) && D_MB)
2555 a |= A_BL;
2556 if (D_rend.attr != a)
2557 SetAttr(a);
2559 else if (D_rend.attr != mc->attr)
2560 SetAttr(mc->attr);
2561 #ifdef COLOR
2562 if (D_rend.color != mc->color
2563 # ifdef COLORS256
2564 || D_rend.colorx != mc->colorx
2565 # endif
2566 # ifdef COLORS16
2567 || D_col16change
2568 # endif
2570 SetColor(rend_getfg(mc), rend_getbg(mc));
2571 #endif
2572 #ifdef FONT
2573 if (D_rend.font != mc->font)
2574 SetFont(mc->font);
2575 #endif
2578 void
2579 SetRenditionMline(ml, x)
2580 struct mline *ml;
2581 int x;
2583 if (!display)
2584 return;
2585 if (nattr2color && D_hascolor && (ml->attr[x] & nattr2color) != 0)
2587 struct mchar mc;
2588 copy_mline2mchar(&mc, ml, x);
2589 SetRendition(&mc);
2590 return;
2592 if (D_hascolor && D_CC8 && (ml->attr[x] & (A_BFG|A_BBG)))
2594 int a = ml->attr[x];
2595 if ((ml->attr[x] & A_BFG) && D_MD)
2596 a |= A_BD;
2597 if ((ml->attr[x] & A_BBG) && D_MB)
2598 a |= A_BL;
2599 if (D_rend.attr != a)
2600 SetAttr(a);
2602 else if (D_rend.attr != ml->attr[x])
2603 SetAttr(ml->attr[x]);
2604 #ifdef COLOR
2605 if (D_rend.color != ml->color[x]
2606 # ifdef COLORS256
2607 || D_rend.colorx != ml->colorx[x]
2608 # endif
2609 # ifdef COLORS16
2610 || D_col16change
2611 # endif
2614 struct mchar mc;
2615 copy_mline2mchar(&mc, ml, x);
2616 SetColor(rend_getfg(&mc), rend_getbg(&mc));
2618 #endif
2619 #ifdef FONT
2620 if (D_rend.font != ml->font[x])
2621 SetFont(ml->font[x]);
2622 #endif
2625 void
2626 MakeStatus(msg)
2627 char *msg;
2629 register char *s, *t;
2630 register int max;
2632 if (!display)
2633 return;
2635 if (D_blocked)
2636 return;
2637 if (!D_tcinited)
2639 debug("tc not inited, just writing msg\n");
2640 if (D_processinputdata)
2641 return; /* XXX: better */
2642 AddStr(msg);
2643 AddStr("\r\n");
2644 Flush();
2645 return;
2647 if (!use_hardstatus || !D_HS)
2649 max = D_width;
2650 if (D_CLP == 0)
2651 max--;
2653 else
2654 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2655 if (D_status)
2657 /* same message? */
2658 if (strcmp(msg, D_status_lastmsg) == 0)
2660 debug("same message - increase timeout");
2661 SetTimeout(&D_statusev, MsgWait);
2662 return;
2664 if (!D_status_bell)
2666 struct timeval now;
2667 int ti;
2668 gettimeofday(&now, NULL);
2669 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
2670 if (ti < MsgMinWait)
2671 DisplaySleep1000(MsgMinWait - ti, 0);
2673 RemoveStatus();
2675 for (s = t = msg; *s && t - msg < max; ++s)
2676 if (*s == BELL)
2677 AddCStr(D_BL);
2678 else if ((unsigned char)*s >= ' ' && *s != 0177)
2679 *t++ = *s;
2680 *t = '\0';
2681 if (t == msg)
2682 return;
2683 if (t - msg >= D_status_buflen)
2685 char *buf;
2686 if (D_status_lastmsg)
2687 buf = realloc(D_status_lastmsg, t - msg + 1);
2688 else
2689 buf = malloc(t - msg + 1);
2690 if (buf)
2692 D_status_lastmsg = buf;
2693 D_status_buflen = t - msg + 1;
2696 if (t - msg < D_status_buflen)
2697 strcpy(D_status_lastmsg, msg);
2698 D_status_len = t - msg;
2699 D_status_lastx = D_x;
2700 D_status_lasty = D_y;
2701 if (!use_hardstatus || D_has_hstatus == HSTATUS_IGNORE || D_has_hstatus == HSTATUS_MESSAGE)
2703 D_status = STATUS_ON_WIN;
2704 debug1("using STATLINE %d\n", STATLINE);
2705 GotoPos(0, STATLINE);
2706 SetRendition(&mchar_so);
2707 InsertMode(0);
2708 AddStr(msg);
2709 if (D_status_len < max)
2711 /* Wayne Davison: add extra space for readability */
2712 D_status_len++;
2713 SetRendition(&mchar_null);
2714 AddChar(' ');
2715 if (D_status_len < max)
2717 D_status_len++;
2718 AddChar(' ');
2719 AddChar('\b');
2721 AddChar('\b');
2723 D_x = -1;
2725 else
2727 D_status = STATUS_ON_HS;
2728 ShowHStatus(msg);
2730 Flush();
2731 if (!display)
2732 return;
2733 if (D_status == STATUS_ON_WIN)
2735 struct display *olddisplay = display;
2736 struct layer *oldflayer = flayer;
2738 ASSERT(D_obuffree == D_obuflen);
2739 /* this is copied over from RemoveStatus() */
2740 D_status = 0;
2741 GotoPos(0, STATLINE);
2742 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2743 GotoPos(D_status_lastx, D_status_lasty);
2744 flayer = D_forecv ? D_forecv->c_layer : 0;
2745 if (flayer)
2746 LaySetCursor();
2747 display = olddisplay;
2748 flayer = oldflayer;
2749 D_status_obuflen = D_obuflen;
2750 D_status_obuffree = D_obuffree;
2751 D_obuffree = D_obuflen = 0;
2752 D_status = STATUS_ON_WIN;
2754 gettimeofday(&D_status_time, NULL);
2755 SetTimeout(&D_statusev, MsgWait);
2756 evenq(&D_statusev);
2757 #ifdef HAVE_BRAILLE
2758 RefreshBraille(); /* let user see multiple Msg()s */
2759 #endif
2762 void
2763 RemoveStatus()
2765 struct display *olddisplay;
2766 struct layer *oldflayer;
2767 int where;
2769 if (!display)
2770 return;
2771 if (!(where = D_status))
2772 return;
2774 debug("RemoveStatus\n");
2775 if (D_status_obuffree >= 0)
2777 D_obuflen = D_status_obuflen;
2778 D_obuffree = D_status_obuffree;
2779 D_status_obuffree = -1;
2781 D_status = 0;
2782 D_status_bell = 0;
2783 evdeq(&D_statusev);
2784 olddisplay = display;
2785 oldflayer = flayer;
2786 if (where == STATUS_ON_WIN)
2788 GotoPos(0, STATLINE);
2789 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2790 GotoPos(D_status_lastx, D_status_lasty);
2792 else
2793 RefreshHStatus();
2794 flayer = D_forecv ? D_forecv->c_layer : 0;
2795 if (flayer)
2796 LaySetCursor();
2797 display = olddisplay;
2798 flayer = oldflayer;
2801 /* refresh the display's hstatus line */
2802 void
2803 ShowHStatus(str)
2804 char *str;
2806 int l, ox, oy, max;
2808 if (D_status == STATUS_ON_WIN && D_has_hstatus == HSTATUS_LASTLINE && STATLINE == D_height-1)
2809 return; /* sorry, in use */
2810 if (D_blocked)
2811 return;
2813 if (D_HS && D_has_hstatus == HSTATUS_HS)
2815 if (!D_hstatus && (str == 0 || *str == 0))
2816 return;
2817 debug("ShowHStatus: using HS\n");
2818 SetRendition(&mchar_null);
2819 InsertMode(0);
2820 if (D_hstatus)
2821 AddCStr(D_DS);
2822 D_hstatus = 0;
2823 if (str == 0 || *str == 0)
2824 return;
2825 AddCStr2(D_TS, 0);
2826 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2827 if ((int)strlen(str) > max)
2828 AddStrn(str, max);
2829 else
2830 AddStr(str);
2831 AddCStr(D_FS);
2832 D_hstatus = 1;
2834 else if (D_has_hstatus == HSTATUS_LASTLINE)
2836 debug("ShowHStatus: using last line\n");
2837 ox = D_x;
2838 oy = D_y;
2839 str = str ? str : "";
2840 l = strlen(str);
2841 if (l > D_width)
2842 l = D_width;
2843 GotoPos(0, D_height - 1);
2844 SetRendition(captionalways || D_cvlist == 0 || D_cvlist->c_next ? &mchar_null: &mchar_so);
2845 PutWinMsg(str, 0, l);
2846 if (!captionalways && D_cvlist && !D_cvlist->c_next)
2847 while (l++ < D_width)
2848 PUTCHARLP(' ');
2849 if (l < D_width)
2850 ClearArea(l, D_height - 1, l, D_width - 1, D_width - 1, D_height - 1, 0, 0);
2851 if (ox != -1 && oy != -1)
2852 GotoPos(ox, oy);
2853 D_hstatus = *str ? 1 : 0;
2854 SetRendition(&mchar_null);
2856 else if (str && *str && D_has_hstatus == HSTATUS_MESSAGE)
2858 debug("ShowHStatus: using message\n");
2859 Msg(0, "%s", str);
2865 * Refreshes the harstatus of the fore window. Shouldn't be here...
2867 void
2868 RefreshHStatus()
2870 char *buf;
2872 evdeq(&D_hstatusev);
2873 if (D_status == STATUS_ON_HS)
2874 return;
2875 buf = MakeWinMsgEv(hstatusstring, D_fore, '%', (D_HS && D_has_hstatus == HSTATUS_HS && D_WS > 0) ? D_WS : D_width - !D_CLP, &D_hstatusev, 0);
2876 if (buf && *buf)
2878 ShowHStatus(buf);
2879 if (D_has_hstatus != HSTATUS_IGNORE && D_hstatusev.timeout.tv_sec)
2880 evenq(&D_hstatusev);
2882 else
2883 ShowHStatus((char *)0);
2886 /*********************************************************************/
2888 * Here come the routines that refresh an arbitrary part of the screen.
2891 void
2892 RefreshAll(isblank)
2893 int isblank;
2895 struct canvas *cv;
2897 ASSERT(display);
2898 debug("Signalling full refresh!\n");
2899 for (cv = D_cvlist; cv; cv = cv->c_next)
2901 CV_CALL(cv, LayRedisplayLine(-1, -1, -1, isblank));
2902 display = cv->c_display; /* just in case! */
2904 RefreshArea(0, 0, D_width - 1, D_height - 1, isblank);
2907 void
2908 RefreshArea(xs, ys, xe, ye, isblank)
2909 int xs, ys, xe, ye, isblank;
2911 int y;
2912 ASSERT(display);
2913 debug2("Refresh Area: %d,%d", xs, ys);
2914 debug3(" - %d,%d (isblank=%d)\n", xe, ye, isblank);
2915 if (!isblank && xs == 0 && xe == D_width - 1 && ye == D_height - 1 && (ys == 0 || D_CD))
2917 ClearArea(xs, ys, xs, xe, xe, ye, 0, 0);
2918 isblank = 1;
2920 for (y = ys; y <= ye; y++)
2921 RefreshLine(y, xs, xe, isblank);
2924 void
2925 RefreshLine(y, from, to, isblank)
2926 int y, from, to, isblank;
2928 struct viewport *vp, *lvp;
2929 struct canvas *cv, *lcv, *cvlist, *cvlnext;
2930 struct layer *oldflayer;
2931 int xx, yy, l;
2932 char *buf;
2933 struct win *p;
2935 ASSERT(display);
2937 debug2("RefreshLine %d %d", y, from);
2938 debug2(" %d %d\n", to, isblank);
2940 if (D_status == STATUS_ON_WIN && y == STATLINE)
2942 if (to >= D_status_len)
2943 D_status_len = to + 1;
2944 return; /* can't refresh status */
2947 if (y == D_height - 1 && D_has_hstatus == HSTATUS_LASTLINE)
2949 RefreshHStatus();
2950 return;
2953 if (isblank == 0 && D_CE && to == D_width - 1 && from < to)
2955 GotoPos(from, y);
2956 if (D_UT || D_BE)
2957 SetRendition(&mchar_null);
2958 AddCStr(D_CE);
2959 isblank = 1;
2961 while (from <= to)
2963 lcv = 0;
2964 lvp = 0;
2965 for (cv = display->d_cvlist; cv; cv = cv->c_next)
2967 if (y == cv->c_ye + 1 && from >= cv->c_xs && from <= cv->c_xe)
2969 p = Layer2Window(cv->c_layer);
2970 buf = MakeWinMsgEv(captionstring, p, '%', cv->c_xe - cv->c_xs + (cv->c_xe + 1 < D_width || D_CLP), &cv->c_captev, 0);
2971 if (cv->c_captev.timeout.tv_sec)
2972 evenq(&cv->c_captev);
2973 xx = to > cv->c_xe ? cv->c_xe : to;
2974 l = strlen(buf);
2975 GotoPos(from, y);
2976 SetRendition(&mchar_so);
2977 if (l > xx - cv->c_xs + 1)
2978 l = xx - cv->c_xs + 1;
2979 PutWinMsg(buf, from - cv->c_xs, l);
2980 from = cv->c_xs + l;
2981 for (; from <= xx; from++)
2982 PUTCHARLP(' ');
2983 break;
2985 if (from == cv->c_xe + 1 && y >= cv->c_ys && y <= cv->c_ye + 1)
2987 GotoPos(from, y);
2988 SetRendition(&mchar_so);
2989 PUTCHARLP(' ');
2990 from++;
2991 break;
2993 if (y < cv->c_ys || y > cv->c_ye || to < cv->c_xs || from > cv->c_xe)
2994 continue;
2995 debug2("- canvas hit: %d %d", cv->c_xs, cv->c_ys);
2996 debug2(" %d %d\n", cv->c_xe, cv->c_ye);
2997 for (vp = cv->c_vplist; vp; vp = vp->v_next)
2999 debug2(" - vp: %d %d", vp->v_xs, vp->v_ys);
3000 debug2(" %d %d\n", vp->v_xe, vp->v_ye);
3001 /* find leftmost overlapping vp */
3002 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))
3004 lcv = cv;
3005 lvp = vp;
3009 if (cv)
3010 continue; /* we advanced from */
3011 if (lvp == 0)
3012 break;
3013 if (from < lvp->v_xs)
3015 if (!isblank)
3016 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xs - 1);
3017 from = lvp->v_xs;
3020 /* call LayRedisplayLine on canvas lcv viewport lvp */
3021 yy = y - lvp->v_yoff;
3022 xx = to < lvp->v_xe ? to : lvp->v_xe;
3024 if (lcv->c_layer && yy == lcv->c_layer->l_height)
3026 GotoPos(from, y);
3027 SetRendition(&mchar_blank);
3028 while (from <= lvp->v_xe && from - lvp->v_xoff < lcv->c_layer->l_width)
3030 PUTCHARLP('-');
3031 from++;
3033 if (from >= lvp->v_xe + 1)
3034 continue;
3036 if (lcv->c_layer == 0 || yy >= lcv->c_layer->l_height || from - lvp->v_xoff >= lcv->c_layer->l_width)
3038 if (!isblank)
3039 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xe);
3040 from = lvp->v_xe + 1;
3041 continue;
3044 if (xx - lvp->v_xoff >= lcv->c_layer->l_width)
3045 xx = lcv->c_layer->l_width + lvp->v_xoff - 1;
3046 oldflayer = flayer;
3047 flayer = lcv->c_layer;
3048 cvlist = flayer->l_cvlist;
3049 cvlnext = lcv->c_lnext;
3050 flayer->l_cvlist = lcv;
3051 lcv->c_lnext = 0;
3052 LayRedisplayLine(yy, from - lvp->v_xoff, xx - lvp->v_xoff, isblank);
3053 flayer->l_cvlist = cvlist;
3054 lcv->c_lnext = cvlnext;
3055 flayer = oldflayer;
3057 from = xx + 1;
3059 if (!isblank && from <= to)
3060 DisplayLine(&mline_null, &mline_blank, y, from, to);
3063 /*********************************************************************/
3065 /* clear lp_missing by writing the char on the screen. The
3066 * position must be safe.
3068 static void
3069 WriteLP(x2, y2)
3070 int x2, y2;
3072 struct mchar oldrend;
3074 ASSERT(display);
3075 ASSERT(D_lp_missing);
3076 oldrend = D_rend;
3077 debug2("WriteLP(%d,%d)\n", x2, y2);
3078 #ifdef DW_CHARS
3079 if (D_lpchar.mbcs)
3081 if (x2 > 0)
3082 x2--;
3083 else
3084 D_lpchar = mchar_blank;
3086 #endif
3087 /* Can't use PutChar */
3088 GotoPos(x2, y2);
3089 SetRendition(&D_lpchar);
3090 PUTCHAR(D_lpchar.image);
3091 #ifdef DW_CHARS
3092 if (D_lpchar.mbcs)
3093 PUTCHAR(D_lpchar.mbcs);
3094 #endif
3095 D_lp_missing = 0;
3096 SetRendition(&oldrend);
3099 void
3100 ClearLine(oml, y, from, to, bce)
3101 struct mline *oml;
3102 int from, to, y, bce;
3104 int x;
3105 #ifdef COLOR
3106 struct mchar bcechar;
3107 #endif
3109 debug3("ClearLine %d,%d-%d\n", y, from, to);
3110 if (D_UT) /* Safe to erase ? */
3111 SetRendition(&mchar_null);
3112 #ifdef COLOR
3113 if (D_BE)
3114 SetBackColor(bce);
3115 #endif
3116 if (from == 0 && D_CB && (to != D_width - 1 || (D_x == to && D_y == y)) && (!bce || D_BE))
3118 GotoPos(to, y);
3119 AddCStr(D_CB);
3120 return;
3122 if (to == D_width - 1 && D_CE && (!bce || D_BE))
3124 GotoPos(from, y);
3125 AddCStr(D_CE);
3126 return;
3128 if (oml == 0)
3129 oml = &mline_null;
3130 #ifdef COLOR
3131 if (!bce)
3133 DisplayLine(oml, &mline_blank, y, from, to);
3134 return;
3136 bcechar = mchar_blank;
3137 rend_setbg(&bcechar, bce);
3138 for (x = from; x <= to; x++)
3139 copy_mchar2mline(&bcechar, &mline_old, x);
3140 DisplayLine(oml, &mline_old, y, from, to);
3141 #else
3142 DisplayLine(oml, &mline_blank, y, from, to);
3143 #endif
3146 void
3147 DisplayLine(oml, ml, y, from, to)
3148 struct mline *oml, *ml;
3149 int from, to, y;
3151 register int x;
3152 int last2flag = 0, delete_lp = 0;
3154 ASSERT(display);
3155 ASSERT(y >= 0 && y < D_height);
3156 ASSERT(from >= 0 && from < D_width);
3157 ASSERT(to >= 0 && to < D_width);
3158 if (!D_CLP && y == D_bot && to == D_width - 1)
3160 if (D_lp_missing || !cmp_mline(oml, ml, to))
3162 #ifdef DW_CHARS
3163 if ((D_IC || D_IM) && from < to && !dw_left(ml, to, D_encoding))
3164 #else
3165 if ((D_IC || D_IM) && from < to)
3166 #endif
3168 last2flag = 1;
3169 D_lp_missing = 0;
3170 to--;
3172 else
3174 delete_lp = !cmp_mchar_mline(&mchar_blank, oml, to) && (D_CE || D_DC || D_CDC);
3175 D_lp_missing = !cmp_mchar_mline(&mchar_blank, ml, to);
3176 copy_mline2mchar(&D_lpchar, ml, to);
3179 to--;
3181 #ifdef DW_CHARS
3182 if (D_mbcs)
3184 /* finish dw-char (can happen after a wrap) */
3185 debug("DisplayLine finishing kanji\n");
3186 SetRenditionMline(ml, from);
3187 PUTCHAR(ml->image[from]);
3188 from++;
3190 #endif
3191 for (x = from; x <= to; x++)
3193 #if 0 /* no longer needed */
3194 if (x || D_x != D_width || D_y != y - 1)
3195 #endif
3197 if (x < to || x != D_width - 1 || ml->image[x + 1])
3198 if (cmp_mline(oml, ml, x))
3199 continue;
3200 GotoPos(x, y);
3202 #ifdef DW_CHARS
3203 if (dw_right(ml, x, D_encoding))
3205 x--;
3206 debug1("DisplayLine on right side of dw char- x now %d\n", x);
3207 GotoPos(x, y);
3209 if (x == to && dw_left(ml, x, D_encoding))
3210 break; /* don't start new kanji */
3211 #endif
3212 SetRenditionMline(ml, x);
3213 PUTCHAR(ml->image[x]);
3214 #ifdef DW_CHARS
3215 if (dw_left(ml, x, D_encoding))
3216 PUTCHAR(ml->image[++x]);
3217 #endif
3219 #if 0 /* not needed any longer */
3220 /* compare != 0 because ' ' can happen when clipping occures */
3221 if (to == D_width - 1 && y < D_height - 1 && D_x == D_width && ml->image[to + 1])
3222 GotoPos(0, y + 1);
3223 #endif
3224 if (last2flag)
3226 GotoPos(x, y);
3227 SetRenditionMline(ml, x + 1);
3228 PUTCHAR(ml->image[x + 1]);
3229 GotoPos(x, y);
3230 SetRenditionMline(ml, x);
3231 INSERTCHAR(ml->image[x]);
3233 else if (delete_lp)
3235 if (D_UT)
3236 SetRendition(&mchar_null);
3237 if (D_DC)
3238 AddCStr(D_DC);
3239 else if (D_CDC)
3240 AddCStr2(D_CDC, 1);
3241 else if (D_CE)
3242 AddCStr(D_CE);
3246 void
3247 PutChar(c, x, y)
3248 struct mchar *c;
3249 int x, y;
3251 GotoPos(x, y);
3252 SetRendition(c);
3253 PUTCHARLP(c->image);
3254 #ifdef DW_CHARS
3255 if (c->mbcs)
3257 # ifdef UTF8
3258 if (D_encoding == UTF8)
3259 D_rend.font = 0;
3260 # endif
3261 PUTCHARLP(c->mbcs);
3263 #endif
3266 void
3267 InsChar(c, x, xe, y, oml)
3268 struct mchar *c;
3269 int x, xe, y;
3270 struct mline *oml;
3272 GotoPos(x, y);
3273 if (y == D_bot && !D_CLP)
3275 if (x == D_width - 1)
3277 D_lp_missing = 1;
3278 D_lpchar = *c;
3279 return;
3281 if (xe == D_width - 1)
3282 D_lp_missing = 0;
3284 if (x == xe)
3286 SetRendition(c);
3287 PUTCHARLP(c->image);
3288 return;
3290 if (!(D_IC || D_CIC || D_IM) || xe != D_width - 1)
3292 RefreshLine(y, x, xe, 0);
3293 GotoPos(x + 1, y);
3294 /* UpdateLine(oml, y, x, xe); */
3295 return;
3297 InsertMode(1);
3298 if (!D_insert)
3300 #ifdef DW_CHARS
3301 if (c->mbcs && D_IC)
3302 AddCStr(D_IC);
3303 if (D_IC)
3304 AddCStr(D_IC);
3305 else
3306 AddCStr2(D_CIC, c->mbcs ? 2 : 1);
3307 #else
3308 if (D_IC)
3309 AddCStr(D_IC);
3310 else
3311 AddCStr2(D_CIC, 1);
3312 #endif
3314 SetRendition(c);
3315 RAW_PUTCHAR(c->image);
3316 #ifdef DW_CHARS
3317 if (c->mbcs)
3319 # ifdef UTF8
3320 if (D_encoding == UTF8)
3321 D_rend.font = 0;
3322 # endif
3323 if (D_x == D_width - 1)
3324 PUTCHARLP(c->mbcs);
3325 else
3326 RAW_PUTCHAR(c->mbcs);
3328 #endif
3331 void
3332 WrapChar(c, x, y, xs, ys, xe, ye, ins)
3333 struct mchar *c;
3334 int x, y;
3335 int xs, ys, xe, ye;
3336 int ins;
3338 int bce;
3340 #ifdef COLOR
3341 bce = rend_getbg(c);
3342 #else
3343 bce = 0;
3344 #endif
3345 debug("WrapChar:");
3346 debug2(" x %d y %d", x, y);
3347 debug2(" Dx %d Dy %d", D_x, D_y);
3348 debug2(" xs %d ys %d", xs, ys);
3349 debug3(" xe %d ye %d ins %d\n", xe, ye, ins);
3350 if (xs != 0 || x != D_width || !D_AM)
3352 if (y == ye)
3353 ScrollV(xs, ys, xe, ye, 1, bce);
3354 else if (y < D_height - 1)
3355 y++;
3356 if (ins)
3357 InsChar(c, xs, xe, y, 0);
3358 else
3359 PutChar(c, xs, y);
3360 return;
3362 if (y == ye) /* we have to scroll */
3364 debug("- scrolling\n");
3365 ChangeScrollRegion(ys, ye);
3366 if (D_bot != y || D_x != D_width || (!bce && !D_BE))
3368 debug("- have to call ScrollV\n");
3369 ScrollV(xs, ys, xe, ye, 1, bce);
3370 y--;
3373 else if (y == D_bot) /* remove unusable region? */
3374 ChangeScrollRegion(0, D_height - 1);
3375 if (D_x != D_width || D_y != y)
3377 if (D_CLP && y >= 0) /* don't even try if !LP */
3378 RefreshLine(y, D_width - 1, D_width - 1, 0);
3379 debug2("- refresh last char -> x,y now %d,%d\n", D_x, D_y);
3380 if (D_x != D_width || D_y != y) /* sorry, no bonus */
3382 if (y == ye)
3383 ScrollV(xs, ys, xe, ye, 1, bce);
3384 GotoPos(xs, y == ye || y == D_height - 1 ? y : y + 1);
3387 debug("- writeing new char");
3388 if (y != ye && y < D_height - 1)
3389 y++;
3390 if (ins != D_insert)
3391 InsertMode(ins);
3392 if (ins && !D_insert)
3394 InsChar(c, 0, xe, y, 0);
3395 debug2(" -> done with insert (%d,%d)\n", D_x, D_y);
3396 return;
3398 D_y = y;
3399 D_x = 0;
3400 SetRendition(c);
3401 RAW_PUTCHAR(c->image);
3402 #ifdef DW_CHARS
3403 if (c->mbcs)
3405 # ifdef UTF8
3406 if (D_encoding == UTF8)
3407 D_rend.font = 0;
3408 # endif
3409 RAW_PUTCHAR(c->mbcs);
3411 #endif
3412 debug2(" -> done (%d,%d)\n", D_x, D_y);
3416 ResizeDisplay(wi, he)
3417 int wi, he;
3419 ASSERT(display);
3420 debug2("ResizeDisplay: to (%d,%d).\n", wi, he);
3421 if (D_width == wi && D_height == he)
3423 debug("ResizeDisplay: No change\n");
3424 return 0;
3426 if (D_width != wi && (D_height == he || !D_CWS) && D_CZ0 && (wi == Z0width || wi == Z1width))
3428 debug("ResizeDisplay: using Z0/Z1\n");
3429 AddCStr(wi == Z0width ? D_CZ0 : D_CZ1);
3430 ChangeScreenSize(wi, D_height, 0);
3431 return (he == D_height) ? 0 : -1;
3433 if (D_CWS)
3435 debug("ResizeDisplay: using WS\n");
3436 AddCStr(tgoto(D_CWS, wi, he));
3437 ChangeScreenSize(wi, he, 0);
3438 return 0;
3440 return -1;
3443 void
3444 ChangeScrollRegion(newtop, newbot)
3445 int newtop, newbot;
3447 if (display == 0)
3448 return;
3449 if (newtop == newbot)
3450 return; /* xterm etc can't do it */
3451 if (newtop == -1)
3452 newtop = 0;
3453 if (newbot == -1)
3454 newbot = D_height - 1;
3455 if (D_CS == 0)
3457 D_top = 0;
3458 D_bot = D_height - 1;
3459 return;
3461 if (D_top == newtop && D_bot == newbot)
3462 return;
3463 debug2("ChangeScrollRegion: (%d - %d)\n", newtop, newbot);
3464 AddCStr(tgoto(D_CS, newbot, newtop));
3465 D_top = newtop;
3466 D_bot = newbot;
3467 D_y = D_x = -1; /* Just in case... */
3470 #ifdef RXVT_OSC
3471 void
3472 SetXtermOSC(i, s)
3473 int i;
3474 char *s;
3476 static char oscs[] = "1;\000\00020;\00039;\00049;\000";
3478 ASSERT(display);
3479 if (!D_CXT)
3480 return;
3481 if (!s)
3482 s = "";
3483 if (!D_xtermosc[i] && !*s)
3484 return;
3485 if (i == 0 && !*s)
3486 s = "screen"; /* always set icon name */
3487 if (i == 1 && !*s)
3488 s = ""; /* no background */
3489 if (i == 2 && !*s)
3490 s = "black"; /* black text */
3491 if (i == 3 && !*s)
3492 s = "white"; /* on white background */
3493 D_xtermosc[i] = 1;
3494 AddStr("\033]");
3495 AddStr(oscs + i * 4);
3496 AddStr(s);
3497 AddChar(7);
3500 void
3501 ClearAllXtermOSC()
3503 int i;
3504 for (i = 3; i >= 0; i--)
3505 SetXtermOSC(i, 0);
3507 #endif
3510 * Output buffering routines
3513 void
3514 AddStr(str)
3515 char *str;
3517 register char c;
3519 ASSERT(display);
3521 #ifdef UTF8
3522 if (D_encoding == UTF8)
3524 while ((c = *str++))
3525 AddUtf8((unsigned char)c);
3526 return;
3528 #endif
3529 while ((c = *str++))
3530 AddChar(c);
3533 void
3534 AddStrn(str, n)
3535 char *str;
3536 int n;
3538 register char c;
3540 ASSERT(display);
3541 #ifdef UTF8
3542 if (D_encoding == UTF8)
3544 while ((c = *str++) && n-- > 0)
3545 AddUtf8((unsigned char)c);
3547 else
3548 #endif
3549 while ((c = *str++) && n-- > 0)
3550 AddChar(c);
3551 while (n-- > 0)
3552 AddChar(' ');
3555 void
3556 Flush()
3558 register int l;
3559 register char *p;
3561 ASSERT(display);
3562 l = D_obufp - D_obuf;
3563 debug1("Flush(): %d\n", l);
3564 if (l == 0)
3565 return;
3566 ASSERT(l + D_obuffree == D_obuflen);
3567 if (D_userfd < 0)
3569 D_obuffree += l;
3570 D_obufp = D_obuf;
3571 return;
3573 p = D_obuf;
3574 if (fcntl(D_userfd, F_SETFL, 0))
3575 debug1("Warning: BLOCK fcntl failed: %d\n", errno);
3576 while (l)
3578 register int wr;
3579 wr = write(D_userfd, p, l);
3580 if (wr <= 0)
3582 if (errno == EINTR)
3583 continue;
3584 debug1("Writing to display: %d\n", errno);
3585 wr = l;
3587 if (!display)
3588 return;
3589 D_obuffree += wr;
3590 p += wr;
3591 l -= wr;
3593 D_obuffree += l;
3594 D_obufp = D_obuf;
3595 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
3596 debug1("Warning: NBLOCK fcntl failed: %d\n", errno);
3597 if (D_blocked == 1)
3598 D_blocked = 0;
3599 D_blocked_fuzz = 0;
3602 void
3603 freetty()
3605 if (D_userfd >= 0)
3606 close(D_userfd);
3607 debug1("did freetty %d\n", D_userfd);
3608 D_userfd = -1;
3609 D_obufp = 0;
3610 D_obuffree = 0;
3611 if (D_obuf)
3612 free(D_obuf);
3613 D_obuf = 0;
3614 D_obuflen = 0;
3615 D_obuflenmax = -D_obufmax;
3616 D_blocked = 0;
3617 D_blocked_fuzz = 0;
3621 * Asynchronous output routines by
3622 * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
3625 void
3626 Resize_obuf()
3628 register int ind;
3630 ASSERT(display);
3631 if (D_status_obuffree >= 0)
3633 ASSERT(D_obuffree == -1);
3634 if (!D_status_bell)
3636 struct timeval now;
3637 int ti;
3638 gettimeofday(&now, NULL);
3639 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
3640 if (ti < MsgMinWait)
3641 DisplaySleep1000(MsgMinWait - ti, 0);
3643 RemoveStatus();
3644 if (--D_obuffree > 0) /* redo AddChar decrement */
3645 return;
3647 if (D_obuflen && D_obuf)
3649 ind = D_obufp - D_obuf;
3650 D_obuflen += GRAIN;
3651 D_obuffree += GRAIN;
3652 D_obuf = realloc(D_obuf, D_obuflen);
3654 else
3656 ind = 0;
3657 D_obuflen = GRAIN;
3658 D_obuffree = GRAIN;
3659 D_obuf = malloc(D_obuflen);
3661 if (!D_obuf)
3662 Panic(0, "Out of memory");
3663 D_obufp = D_obuf + ind;
3664 D_obuflenmax = D_obuflen - D_obufmax;
3665 debug1("ResizeObuf: resized to %d\n", D_obuflen);
3668 void
3669 DisplaySleep1000(n, eat)
3670 int n;
3671 int eat;
3673 char buf;
3674 fd_set r;
3675 struct timeval t;
3677 if (n <= 0)
3678 return;
3679 if (!display)
3681 debug("DisplaySleep has no display sigh\n");
3682 sleep1000(n);
3683 return;
3685 t.tv_usec = (n % 1000) * 1000;
3686 t.tv_sec = n / 1000;
3687 FD_ZERO(&r);
3688 FD_SET(D_userfd, &r);
3689 if (select(FD_SETSIZE, &r, (fd_set *)0, (fd_set *)0, &t) > 0)
3691 debug("display activity stopped sleep\n");
3692 if (eat)
3693 read(D_userfd, &buf, 1);
3695 debug2("DisplaySleep(%d) ending, eat was %d\n", n, eat);
3698 #ifdef AUTO_NUKE
3699 void
3700 NukePending()
3701 {/* Nuke pending output in current display, clear screen */
3702 register int len;
3703 int oldtop = D_top, oldbot = D_bot;
3704 struct mchar oldrend;
3705 int oldkeypad = D_keypad, oldcursorkeys = D_cursorkeys;
3706 int oldcurvis = D_curvis;
3707 int oldmouse = D_mouse;
3709 oldrend = D_rend;
3710 len = D_obufp - D_obuf;
3711 debug1("NukePending: nuking %d chars\n", len);
3713 /* Throw away any output that we can... */
3714 # ifdef POSIX
3715 tcflush(D_userfd, TCOFLUSH);
3716 # else
3717 # ifdef TCFLSH
3718 (void) ioctl(D_userfd, TCFLSH, (char *) 1);
3719 # endif
3720 # endif
3722 D_obufp = D_obuf;
3723 D_obuffree += len;
3724 D_top = D_bot = -1;
3725 AddCStr(D_TI);
3726 AddCStr(D_IS);
3727 /* Turn off all attributes. (Tim MacKenzie) */
3728 if (D_ME)
3729 AddCStr(D_ME);
3730 else
3732 #ifdef COLOR
3733 if (D_hascolor)
3734 AddStr("\033[m"); /* why is D_ME not set? */
3735 #endif
3736 AddCStr(D_SE);
3737 AddCStr(D_UE);
3739 /* Check for toggle */
3740 if (D_IM && strcmp(D_IM, D_EI))
3741 AddCStr(D_EI);
3742 D_insert = 0;
3743 /* Check for toggle */
3744 #ifdef MAPKEYS
3745 if (D_KS && strcmp(D_KS, D_KE))
3746 AddCStr(D_KS);
3747 if (D_CCS && strcmp(D_CCS, D_CCE))
3748 AddCStr(D_CCS);
3749 #else
3750 if (D_KS && strcmp(D_KS, D_KE))
3751 AddCStr(D_KE);
3752 D_keypad = 0;
3753 if (D_CCS && strcmp(D_CCS, D_CCE))
3754 AddCStr(D_CCE);
3755 D_cursorkeys = 0;
3756 #endif
3757 AddCStr(D_CE0);
3758 D_rend = mchar_null;
3759 D_atyp = 0;
3760 AddCStr(D_DS);
3761 D_hstatus = 0;
3762 AddCStr(D_VE);
3763 D_curvis = 0;
3764 ChangeScrollRegion(oldtop, oldbot);
3765 SetRendition(&oldrend);
3766 KeypadMode(oldkeypad);
3767 CursorkeysMode(oldcursorkeys);
3768 CursorVisibility(oldcurvis);
3769 MouseMode(oldmouse);
3770 if (D_CWS)
3772 debug("ResizeDisplay: using WS\n");
3773 AddCStr(tgoto(D_CWS, D_width, D_height));
3775 else if (D_CZ0 && (D_width == Z0width || D_width == Z1width))
3777 debug("ResizeDisplay: using Z0/Z1\n");
3778 AddCStr(D_width == Z0width ? D_CZ0 : D_CZ1);
3781 #endif /* AUTO_NUKE */
3783 #ifdef linux
3784 /* linux' select can't handle flow control, so wait 100ms if
3785 * we get EAGAIN
3787 static void
3788 disp_writeev_eagain(ev, data)
3789 struct event *ev;
3790 char *data;
3792 display = (struct display *)data;
3793 evdeq(&D_writeev);
3794 D_writeev.type = EV_WRITE;
3795 D_writeev.handler = disp_writeev_fn;
3796 evenq(&D_writeev);
3798 #endif
3800 static void
3801 disp_writeev_fn(ev, data)
3802 struct event *ev;
3803 char *data;
3805 int len, size = OUTPUT_BLOCK_SIZE;
3807 display = (struct display *)data;
3808 len = D_obufp - D_obuf;
3809 if (len < size)
3810 size = len;
3811 ASSERT(len >= 0);
3812 size = write(D_userfd, D_obuf, size);
3813 if (size >= 0)
3815 len -= size;
3816 if (len)
3818 bcopy(D_obuf + size, D_obuf, len);
3819 debug2("ASYNC: wrote %d - remaining %d\n", size, len);
3821 D_obufp -= size;
3822 D_obuffree += size;
3823 if (D_blocked_fuzz)
3825 D_blocked_fuzz -= size;
3826 if (D_blocked_fuzz < 0)
3827 D_blocked_fuzz = 0;
3829 if (D_blockedev.queued)
3831 if (D_obufp - D_obuf > D_obufmax / 2)
3833 debug2("%s: resetting timeout to %g secs\n", D_usertty, D_nonblock/1000.);
3834 SetTimeout(&D_blockedev, D_nonblock);
3836 else
3838 debug1("%s: deleting blocked timeout\n", D_usertty);
3839 evdeq(&D_blockedev);
3842 if (D_blocked == 1 && D_obuf == D_obufp)
3844 /* empty again, restart output */
3845 debug1("%s: buffer empty, unblocking\n", D_usertty);
3846 D_blocked = 0;
3847 Activate(D_fore ? D_fore->w_norefresh : 0);
3848 D_blocked_fuzz = D_obufp - D_obuf;
3851 else
3853 #ifdef linux
3854 /* linux flow control is badly broken */
3855 if (errno == EAGAIN)
3857 evdeq(&D_writeev);
3858 D_writeev.type = EV_TIMEOUT;
3859 D_writeev.handler = disp_writeev_eagain;
3860 SetTimeout(&D_writeev, 100);
3861 evenq(&D_writeev);
3863 #endif
3864 if (errno != EINTR && errno != EAGAIN)
3865 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3866 if (errno != EWOULDBLOCK)
3867 #endif
3868 Msg(errno, "Error writing output to display");
3872 static void
3873 disp_readev_fn(ev, data)
3874 struct event *ev;
3875 char *data;
3877 int size;
3878 char buf[IOSIZE];
3879 struct canvas *cv;
3881 display = (struct display *)data;
3883 /* Hmmmm... a bit ugly... */
3884 if (D_forecv)
3885 for (cv = D_forecv->c_layer->l_cvlist; cv; cv = cv->c_lnext)
3887 display = cv->c_display;
3888 if (D_status == STATUS_ON_WIN)
3889 RemoveStatus();
3892 display = (struct display *)data;
3893 if (D_fore == 0)
3894 size = IOSIZE;
3895 else
3897 #ifdef PSEUDOS
3898 if (W_UWP(D_fore))
3899 size = sizeof(D_fore->w_pwin->p_inbuf) - D_fore->w_pwin->p_inlen;
3900 else
3901 #endif
3902 size = sizeof(D_fore->w_inbuf) - D_fore->w_inlen;
3905 if (size > IOSIZE)
3906 size = IOSIZE;
3907 if (size <= 0)
3908 size = 1; /* Always allow one char for command keys */
3910 size = read(D_userfd, buf, size);
3911 if (size < 0)
3913 if (errno == EINTR || errno == EAGAIN)
3914 return;
3915 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3916 if (errno == EWOULDBLOCK)
3917 return;
3918 #endif
3919 debug1("Read error: %d - hangup!\n", errno);
3920 Hangup();
3921 sleep(1);
3922 return;
3924 else if (size == 0)
3926 debug("Found EOF - hangup!\n");
3927 Hangup();
3928 sleep(1);
3929 return;
3931 if (D_blocked == 4)
3933 D_blocked = 0;
3934 #ifdef BLANKER_PRG
3935 KillBlanker();
3936 #endif
3937 Activate(D_fore ? D_fore->w_norefresh : 0);
3938 ResetIdle();
3939 return;
3941 #ifdef ZMODEM
3942 if (D_blocked > 1) /* 2, 3 */
3944 char *bufp;
3945 struct win *p;
3947 flayer = 0;
3948 for (p = windows; p ; p = p->w_next)
3949 if (p->w_zdisplay == display)
3951 flayer = &p->w_layer;
3952 bufp = buf;
3953 while (size > 0)
3954 LayProcess(&bufp, &size);
3955 return;
3957 debug("zmodem window gone, deblocking display");
3958 zmodem_abort(0, display);
3960 #endif
3961 if (idletimo > 0)
3962 ResetIdle();
3963 if (D_fore)
3964 D_fore->w_lastdisp = display;
3965 if (D_mouse && D_forecv)
3967 unsigned char *bp = (unsigned char *)buf;
3968 int x, y, i = size;
3970 /* XXX this assumes that the string is read in as a whole... */
3971 for (i = size; i > 0; i--, bp++)
3973 if (i > 5 && bp[0] == 033 && bp[1] == '[' && bp[2] == 'M')
3975 bp++;
3976 i--;
3978 else if (i < 5 || bp[0] != 0233 || bp[1] != 'M')
3979 continue;
3980 x = bp[3] - 33;
3981 y = bp[4] - 33;
3982 if (x >= D_forecv->c_xs && x <= D_forecv->c_xe && y >= D_forecv->c_ys && y <= D_forecv->c_ye)
3984 x -= D_forecv->c_xoff;
3985 y -= D_forecv->c_yoff;
3986 if (x >= 0 && x < D_forecv->c_layer->l_width && y >= 0 && y < D_forecv->c_layer->l_height)
3988 bp[3] = x + 33;
3989 bp[4] = y + 33;
3990 i -= 4;
3991 bp += 4;
3992 continue;
3995 if (bp[0] == '[')
3997 bcopy((char *)bp + 1, (char *)bp, i);
3998 bp--;
3999 size--;
4001 if (i > 5)
4002 bcopy((char *)bp + 5, (char *)bp, i - 5);
4003 bp--;
4004 i -= 4;
4005 size -= 5;
4008 #ifdef ENCODINGS
4009 if (D_encoding != (D_forecv ? D_forecv->c_layer->l_encoding : 0))
4011 int i, j, c, enc;
4012 char buf2[IOSIZE * 2 + 10];
4013 enc = D_forecv ? D_forecv->c_layer->l_encoding : 0;
4014 for (i = j = 0; i < size; i++)
4016 c = ((unsigned char *)buf)[i];
4017 c = DecodeChar(c, D_encoding, &D_decodestate);
4018 if (c == -2)
4019 i--; /* try char again */
4020 if (c < 0)
4021 continue;
4022 if (pastefont)
4024 int font = 0;
4025 j += EncodeChar(buf2 + j, c, enc, &font);
4026 j += EncodeChar(buf2 + j, -1, enc, &font);
4028 else
4029 j += EncodeChar(buf2 + j, c, enc, 0);
4030 if (j > (int)sizeof(buf2) - 10) /* just in case... */
4031 break;
4033 (*D_processinput)(buf2, j);
4034 return;
4036 #endif
4037 (*D_processinput)(buf, size);
4040 static void
4041 disp_status_fn(ev, data)
4042 struct event *ev;
4043 char *data;
4045 display = (struct display *)data;
4046 debug1("disp_status_fn for display %x\n", (int)display);
4047 if (D_status)
4048 RemoveStatus();
4051 static void
4052 disp_hstatus_fn(ev, data)
4053 struct event *ev;
4054 char *data;
4056 display = (struct display *)data;
4057 if (D_status == STATUS_ON_HS)
4059 SetTimeout(ev, 1);
4060 evenq(ev);
4061 return;
4063 RefreshHStatus();
4066 static void
4067 disp_blocked_fn(ev, data)
4068 struct event *ev;
4069 char *data;
4071 struct win *p;
4073 display = (struct display *)data;
4074 debug1("blocked timeout %s\n", D_usertty);
4075 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
4077 debug("stopping output to display\n");
4078 D_blocked = 1;
4079 /* re-enable all windows */
4080 for (p = windows; p; p = p->w_next)
4081 if (p->w_readev.condneg == &D_obuflenmax)
4083 debug1("freeing window #%d\n", p->w_number);
4084 p->w_readev.condpos = p->w_readev.condneg = 0;
4089 static void
4090 cv_winid_fn(ev, data)
4091 struct event *ev;
4092 char *data;
4094 int ox, oy;
4095 struct canvas *cv = (struct canvas *)data;
4097 display = cv->c_display;
4098 if (D_status == STATUS_ON_WIN)
4100 SetTimeout(ev, 1);
4101 evenq(ev);
4102 return;
4104 ox = D_x;
4105 oy = D_y;
4106 if (cv->c_ye + 1 < D_height)
4107 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
4108 if (ox != -1 && oy != -1)
4109 GotoPos(ox, oy);
4112 #ifdef MAPKEYS
4113 static void
4114 disp_map_fn(ev, data)
4115 struct event *ev;
4116 char *data;
4118 char *p;
4119 int l, i;
4120 unsigned char *q;
4121 display = (struct display *)data;
4122 debug("Flushing map sequence\n");
4123 if (!(l = D_seql))
4124 return;
4125 p = (char *)D_seqp - l;
4126 D_seqp = D_kmaps + 3;
4127 D_seql = 0;
4128 if ((q = D_seqh) != 0)
4130 D_seqh = 0;
4131 i = q[0] << 8 | q[1];
4132 i &= ~KMAP_NOTIMEOUT;
4133 debug1("Mapping former hit #%d - ", i);
4134 debug2("%d(%s) - ", q[2], q + 3);
4135 if (StuffKey(i))
4136 ProcessInput2((char *)q + 3, q[2]);
4137 if (display == 0)
4138 return;
4139 l -= q[2];
4140 p += q[2];
4142 else
4143 D_dontmap = 1;
4144 ProcessInput(p, l);
4146 #endif
4148 static void
4149 disp_idle_fn(ev, data)
4150 struct event *ev;
4151 char *data;
4153 struct display *olddisplay;
4154 display = (struct display *)data;
4155 debug("idle timeout\n");
4156 if (idletimo <= 0 || idleaction.nr == RC_ILLEGAL)
4157 return;
4158 olddisplay = display;
4159 flayer = D_forecv->c_layer;
4160 fore = D_fore;
4161 DoAction(&idleaction, -1);
4162 if (idleaction.nr == RC_BLANKER)
4163 return;
4164 for (display = displays; display; display = display->d_next)
4165 if (olddisplay == display)
4166 break;
4167 if (display)
4168 ResetIdle();
4171 void
4172 ResetIdle()
4174 if (idletimo > 0)
4176 SetTimeout(&D_idleev, idletimo);
4177 if (!D_idleev.queued)
4178 evenq(&D_idleev);
4180 else
4181 evdeq(&D_idleev);
4185 #ifdef BLANKER_PRG
4187 static void
4188 disp_blanker_fn(ev, data)
4189 struct event *ev;
4190 char *data;
4192 char buf[IOSIZE], *b;
4193 int size;
4195 display = (struct display *)data;
4196 size = read(D_blankerev.fd, buf, IOSIZE);
4197 if (size <= 0)
4199 evdeq(&D_blankerev);
4200 close(D_blankerev.fd);
4201 D_blankerev.fd = -1;
4202 return;
4204 for (b = buf; size; size--)
4205 AddChar(*b++);
4208 void
4209 KillBlanker()
4211 int oldtop = D_top, oldbot = D_bot;
4212 struct mchar oldrend;
4214 if (D_blankerev.fd == -1)
4215 return;
4216 if (D_blocked == 4)
4217 D_blocked = 0;
4218 evdeq(&D_blankerev);
4219 close(D_blankerev.fd);
4220 D_blankerev.fd = -1;
4221 Kill(D_blankerpid, SIGHUP);
4222 D_top = D_bot = -1;
4223 oldrend = D_rend;
4224 if (D_ME)
4226 AddCStr(D_ME);
4227 AddCStr(D_ME);
4229 else
4231 #ifdef COLOR
4232 if (D_hascolor)
4233 AddStr("\033[m\033[m"); /* why is D_ME not set? */
4234 #endif
4235 AddCStr(D_SE);
4236 AddCStr(D_UE);
4238 AddCStr(D_VE);
4239 AddCStr(D_CE0);
4240 D_rend = mchar_null;
4241 D_atyp = 0;
4242 D_curvis = 0;
4243 D_x = D_y = -1;
4244 ChangeScrollRegion(oldtop, oldbot);
4245 SetRendition(&oldrend);
4246 ClearAll();
4249 void
4250 RunBlanker(cmdv)
4251 char **cmdv;
4253 char *m;
4254 int pid;
4255 int slave = -1;
4256 char termname[30];
4257 #ifndef TIOCSWINSZ
4258 char libuf[20], cobuf[20];
4259 #endif
4260 char **np;
4262 strcpy(termname, "TERM=");
4263 strncpy(termname + 5, D_termname, sizeof(termname) - 6);
4264 termname[sizeof(termname) - 1] = 0;
4265 KillBlanker();
4266 D_blankerpid = -1;
4267 if ((D_blankerev.fd = OpenPTY(&m)) == -1)
4269 Msg(0, "OpenPty failed");
4270 return;
4272 #ifdef O_NOCTTY
4273 if (pty_preopen)
4275 if ((slave = open(m, O_RDWR|O_NOCTTY)) == -1)
4277 Msg(errno, "%s", m);
4278 close(D_blankerev.fd);
4279 D_blankerev.fd = -1;
4280 return;
4283 #endif
4284 switch (pid = (int)fork())
4286 case -1:
4287 Msg(errno, "fork");
4288 close(D_blankerev.fd);
4289 D_blankerev.fd = -1;
4290 return;
4291 case 0:
4292 displays = 0;
4293 #ifdef DEBUG
4294 if (dfp && dfp != stderr)
4295 fclose(dfp);
4296 #endif
4297 if (setgid(real_gid) || setuid(real_uid))
4298 Panic(errno, "setuid/setgid");
4299 brktty(D_userfd);
4300 freetty();
4301 close(0);
4302 close(1);
4303 close(2);
4304 closeallfiles(slave);
4305 if (open(m, O_RDWR))
4306 Panic(errno, "Cannot open %s", m);
4307 dup(0);
4308 dup(0);
4309 if (slave != -1)
4310 close(slave);
4311 InitPTY(0);
4312 fgtty(0);
4313 SetTTY(0, &D_OldMode);
4314 np = NewEnv + 3;
4315 *np++ = NewEnv[0];
4316 *np++ = termname;
4317 #ifdef TIOCSWINSZ
4318 glwz.ws_col = D_width;
4319 glwz.ws_row = D_height;
4320 (void)ioctl(0, TIOCSWINSZ, (char *)&glwz);
4321 #else
4322 sprintf(libuf, "LINES=%d", D_height);
4323 sprintf(libuf, "COLUMNS=%d", D_width);
4324 *np++ = libuf;
4325 *np++ = cobuf;
4326 #endif
4327 #ifdef SIGPIPE
4328 signal(SIGPIPE, SIG_DFL);
4329 #endif
4330 display = 0;
4331 execvpe(*cmdv, cmdv, NewEnv + 3);
4332 Panic(errno, *cmdv);
4333 default:
4334 break;
4336 D_blankerpid = pid;
4337 evenq(&D_blankerev);
4338 D_blocked = 4;
4339 ClearAll();
4342 #endif
4344 struct layout *layouts;
4345 struct layout *laytab[MAXLAY];
4346 struct layout *layout_last, layout_last_marker;
4347 struct layout *layout_attach = &layout_last_marker;
4349 void
4350 FreeLayoutCv(cv)
4351 struct canvas *cv;
4353 for (; cv; cv = cv->c_slnext)
4354 if (cv->c_slperp)
4356 FreeLayoutCv(cv->c_slperp);
4357 free(cv->c_slperp);
4358 cv->c_slperp = 0;
4362 static void
4363 DupLayoutCv(cvf, cvt, save)
4364 struct canvas *cvf, *cvt;
4365 int save;
4367 while(cvf)
4369 cvt->c_slorient = cvf->c_slorient;
4370 cvt->c_slweight = cvf->c_slweight;
4371 if (cvf == D_forecv)
4372 D_forecv = cvt;
4373 if (!save)
4375 cvt->c_display = display;
4376 if (!cvf->c_slperp)
4378 cvt->c_captev.type = EV_TIMEOUT;
4379 cvt->c_captev.data = (char *)cvt;
4380 cvt->c_captev.handler = cv_winid_fn;
4381 cvt->c_blank.l_cvlist = 0;
4382 cvt->c_blank.l_layfn = &BlankLf;
4383 cvt->c_blank.l_bottom = &cvt->c_blank;
4385 cvt->c_layer = cvf->c_layer;
4387 else
4389 struct win *p = cvf->c_layer ? Layer2Window(cvf->c_layer) : 0;
4390 cvt->c_layer = p ? &p->w_layer : 0;
4392 if (cvf->c_slperp)
4394 cvt->c_slperp = (struct canvas *)calloc(1, sizeof(struct canvas));
4395 cvt->c_slperp->c_slback = cvt;
4396 DupLayoutCv(cvf->c_slperp, cvt->c_slperp, save);
4398 if (cvf->c_slnext)
4400 cvt->c_slnext = (struct canvas *)calloc(1, sizeof(struct canvas));
4401 cvt->c_slnext->c_slprev = cvt;
4402 cvt->c_slnext->c_slback = cvt->c_slback;
4404 cvf = cvf->c_slnext;
4405 cvt = cvt->c_slnext;
4409 void
4410 PutWindowCv(cv)
4411 struct canvas *cv;
4413 struct win *p;
4414 for (; cv; cv = cv->c_slnext)
4416 if (cv->c_slperp)
4418 PutWindowCv(cv->c_slperp);
4419 continue;
4421 p = cv->c_layer ? (struct win *)cv->c_layer->l_data : 0;
4422 cv->c_layer = 0;
4423 SetCanvasWindow(cv, p);
4427 struct layout *
4428 CreateLayout(title, startat)
4429 char *title;
4430 int startat;
4432 struct layout *lay;
4433 int i;
4435 if (startat >= MAXLAY || startat < 0)
4436 startat = 0;
4437 for (i = startat; ;)
4439 if (!laytab[i])
4440 break;
4441 if (++i == MAXLAY)
4442 i = 0;
4443 if (i == startat)
4445 Msg(0, "No more layouts\n");
4446 return 0;
4449 lay = (struct layout *)calloc(1, sizeof(*lay));
4450 lay->lay_title = SaveStr(title);
4451 lay->lay_autosave = 1;
4452 lay->lay_number = i;
4453 laytab[i] = lay;
4454 lay->lay_next = layouts;
4455 layouts = lay;
4456 return lay;
4459 void
4460 SaveLayout(name, cv)
4461 char *name;
4462 struct canvas *cv;
4464 struct layout *lay;
4465 struct canvas *fcv;
4466 for (lay = layouts; lay; lay = lay->lay_next)
4467 if (!strcmp(lay->lay_title, name))
4468 break;
4469 if (lay)
4470 FreeLayoutCv(&lay->lay_canvas);
4471 else
4472 lay = CreateLayout(name, 0);
4473 if (!lay)
4474 return;
4475 fcv = D_forecv;
4476 DupLayoutCv(cv, &lay->lay_canvas, 1);
4477 lay->lay_forecv = D_forecv;
4478 D_forecv = fcv;
4479 D_layout = lay;
4482 void
4483 AutosaveLayout(lay)
4484 struct layout *lay;
4486 struct canvas *fcv;
4487 if (!lay || !lay->lay_autosave)
4488 return;
4489 FreeLayoutCv(&lay->lay_canvas);
4490 fcv = D_forecv;
4491 DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
4492 lay->lay_forecv = D_forecv;
4493 D_forecv = fcv;
4496 struct layout *
4497 FindLayout(name)
4498 char *name;
4500 struct layout *lay;
4501 char *s;
4502 int i;
4503 for (i = 0, s = name; *s >= '0' && *s <= '9'; s++)
4504 i = i * 10 + (*s - '0');
4505 if (!*s && s != name && i >= 0 && i < MAXLAY)
4506 return laytab[i];
4507 for (lay = layouts; lay; lay = lay->lay_next)
4508 if (!strcmp(lay->lay_title, name))
4509 break;
4510 return lay;
4513 void
4514 LoadLayout(lay, cv)
4515 struct layout *lay;
4516 struct canvas *cv;
4518 AutosaveLayout(D_layout);
4519 if (!lay)
4521 while (D_canvas.c_slperp)
4522 FreeCanvas(D_canvas.c_slperp);
4523 MakeDefaultCanvas();
4524 SetCanvasWindow(D_forecv, 0);
4525 D_layout = 0;
4526 return;
4528 while (D_canvas.c_slperp)
4529 FreeCanvas(D_canvas.c_slperp);
4530 D_cvlist = 0;
4531 D_forecv = lay->lay_forecv;
4532 DupLayoutCv(&lay->lay_canvas, &D_canvas, 0);
4533 D_canvas.c_ye = D_height - 1 - ((D_canvas.c_slperp && D_canvas.c_slperp->c_slnext) || captionalways) - (D_has_hstatus == HSTATUS_LASTLINE);
4534 ResizeCanvas(&D_canvas);
4535 RecreateCanvasChain();
4536 RethinkDisplayViewports();
4537 PutWindowCv(&D_canvas);
4538 ResizeLayersToCanvases();
4539 D_layout = lay;
4542 void
4543 NewLayout(title, startat)
4544 char *title;
4545 int startat;
4547 struct layout *lay;
4548 struct canvas *fcv;
4550 lay = CreateLayout(title, startat);
4551 if (!lay)
4552 return;
4553 LoadLayout(0, &D_canvas);
4554 fcv = D_forecv;
4555 DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
4556 lay->lay_forecv = D_forecv;
4557 D_forecv = fcv;
4558 D_layout = lay;
4559 lay->lay_autosave = 1;
4562 static char *
4563 AddLayoutsInfo(buf, len, where)
4564 char *buf;
4565 int len;
4566 int where;
4568 char *s, *ss, *t;
4569 struct layout *p, **pp;
4570 int l;
4572 s = ss = buf;
4573 for (pp = laytab; pp < laytab + MAXLAY; pp++)
4575 if (pp - laytab == where && ss == buf)
4576 ss = s;
4577 if ((p = *pp) == 0)
4578 continue;
4579 t = p->lay_title;
4580 l = strlen(t);
4581 if (l > 20)
4582 l = 20;
4583 if (s - buf + l > len - 24)
4584 break;
4585 if (s > buf)
4587 *s++ = ' ';
4588 *s++ = ' ';
4590 sprintf(s, "%d", p->lay_number);
4591 if (p->lay_number == where)
4592 ss = s;
4593 s += strlen(s);
4594 if (display && p == D_layout)
4595 *s++ = '*';
4596 *s++ = ' ';
4597 strncpy(s, t, l);
4598 s += l;
4600 *s = 0;
4601 return ss;
4604 void
4605 ShowLayouts(where)
4606 int where;
4608 char buf[1024];
4609 char *s, *ss;
4611 if (!display)
4612 return;
4613 if (!layouts)
4615 Msg(0, "No layouts defined\n");
4616 return;
4618 if (where == -1 && D_layout)
4619 where = D_layout->lay_number;
4620 ss = AddLayoutsInfo(buf, sizeof(buf), where);
4621 s = buf + strlen(buf);
4622 if (ss - buf > D_width / 2)
4624 ss -= D_width / 2;
4625 if (s - ss < D_width)
4627 ss = s - D_width;
4628 if (ss < buf)
4629 ss = buf;
4632 else
4633 ss = buf;
4634 Msg(0, "%s", ss);