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