Set title bas on the output found on the screen.
[screen-lua.git] / src / display.c
blobcf304439e6e9708c63b1f3246d82b48489932b53
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 SCRIPT
415 broker_inv_obj(display);
416 #endif
417 #ifdef MULTI
418 free((char *)display);
419 #endif
420 display = 0;
423 static void
424 CanvasInitBlank(cv)
425 struct canvas *cv;
427 cv->c_blank.l_cvlist = cv;
428 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
429 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
430 cv->c_blank.l_x = cv->c_blank.l_y = 0;
431 cv->c_blank.l_layfn = &BlankLf;
432 cv->c_blank.l_data = 0;
433 cv->c_blank.l_next = 0;
434 cv->c_blank.l_bottom = &cv->c_blank;
435 cv->c_blank.l_blocking = 0;
436 cv->c_layer = &cv->c_blank;
440 MakeDefaultCanvas()
442 struct canvas *cv;
444 ASSERT(display);
445 if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
446 return -1;
447 cv->c_xs = 0;
448 cv->c_xe = D_width - 1;
449 cv->c_ys = 0;
450 cv->c_ye = D_height - 1 - (D_has_hstatus == HSTATUS_LASTLINE) - captionalways;
451 debug2("MakeDefaultCanvas 0,0 %d,%d\n", cv->c_xe, cv->c_ye);
452 cv->c_xoff = 0;
453 cv->c_yoff = 0;
454 cv->c_next = 0;
455 cv->c_display = display;
456 cv->c_vplist = 0;
457 cv->c_slnext = 0;
458 cv->c_slprev = 0;
459 cv->c_slperp = 0;
460 cv->c_slweight = 1;
461 cv->c_slback = &D_canvas;
462 D_canvas.c_slperp = cv;
463 D_canvas.c_xs = cv->c_xs;
464 D_canvas.c_xe = cv->c_xe;
465 D_canvas.c_ys = cv->c_ys;
466 D_canvas.c_ye = cv->c_ye;
467 cv->c_slorient = SLICE_UNKN;
468 cv->c_captev.type = EV_TIMEOUT;
469 cv->c_captev.data = (char *)cv;
470 cv->c_captev.handler = cv_winid_fn;
472 CanvasInitBlank(cv);
473 cv->c_lnext = 0;
475 D_cvlist = cv;
476 RethinkDisplayViewports();
477 D_forecv = cv; /* default input focus */
478 return 0;
481 static struct canvas **
482 CreateCanvasChainRec(cv, cvp)
483 struct canvas *cv;
484 struct canvas **cvp;
486 for (; cv; cv = cv->c_slnext)
488 if (cv->c_slperp)
489 cvp = CreateCanvasChainRec(cv->c_slperp, cvp);
490 else
492 *cvp = cv;
493 cvp = &cv->c_next;
496 return cvp;
499 void
500 RecreateCanvasChain()
502 struct canvas **cvp;
503 cvp = CreateCanvasChainRec(D_canvas.c_slperp, &D_cvlist);
504 *cvp = 0;
507 static void
508 FreeCanvas(cv)
509 struct canvas *cv;
511 struct viewport *vp, *nvp;
512 struct canvas **cvp;
513 struct win *p;
515 if (cv->c_slprev)
516 cv->c_slprev->c_slnext = cv->c_slnext;
517 if (cv->c_slnext)
518 cv->c_slnext->c_slprev = cv->c_slprev;
519 if (cv->c_slback && cv->c_slback->c_slperp == cv)
520 cv->c_slback->c_slperp = cv->c_slnext ? cv->c_slnext : cv->c_slprev;
521 if (cv->c_slperp)
523 while (cv->c_slperp)
524 FreeCanvas(cv->c_slperp);
525 free(cv);
526 return;
529 if (display)
531 if (D_forecv == cv)
532 D_forecv = 0;
533 /* remove from canvas chain as SetCanvasWindow might call
534 * some layer function */
535 for (cvp = &D_cvlist; *cvp ; cvp = &(*cvp)->c_next)
536 if (*cvp == cv)
538 *cvp = cv->c_next;
539 break;
542 p = cv->c_layer ? Layer2Window(cv->c_layer) : 0;
543 SetCanvasWindow(cv, 0);
544 if (p)
545 WindowChanged(p, 'u');
546 if (flayer == cv->c_layer)
547 flayer = 0;
548 for (vp = cv->c_vplist; vp; vp = nvp)
550 vp->v_canvas = 0;
551 nvp = vp->v_next;
552 vp->v_next = 0;
553 free(vp);
555 evdeq(&cv->c_captev);
556 #ifdef SCRIPT
557 broker_inv_obj(cv);
558 #endif
559 free(cv);
563 CountCanvas(cv)
564 struct canvas *cv;
566 int num = 0;
567 for (; cv; cv = cv->c_slnext)
569 if (cv->c_slperp)
571 struct canvas *cvp;
572 int nump = 1, n;
573 for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
574 if (cvp->c_slperp)
576 n = CountCanvas(cvp->c_slperp);
577 if (n > nump)
578 nump = n;
580 num += nump;
582 else
583 num++;
585 return num;
589 CountCanvasPerp(cv)
590 struct canvas *cv;
592 struct canvas *cvp;
593 int num = 1, n;
594 for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
595 if (cvp->c_slperp)
597 n = CountCanvas(cvp->c_slperp);
598 if (n > num)
599 num = n;
601 return num;
604 void
605 EqualizeCanvas(cv, gflag)
606 struct canvas *cv;
607 int gflag;
609 struct canvas *cv2;
610 for (; cv; cv = cv->c_slnext)
612 if (cv->c_slperp && gflag)
614 cv->c_slweight = CountCanvasPerp(cv);
615 for (cv2 = cv->c_slperp; cv2; cv2 = cv2->c_slnext)
616 if (cv2->c_slperp)
617 EqualizeCanvas(cv2->c_slperp, gflag);
619 else
620 cv->c_slweight = 1;
624 void
625 ResizeCanvas(cv)
626 struct canvas *cv;
628 struct canvas *cv2, *cvn, *fcv;
629 int nh, i, maxi, hh, m, w, wsum;
630 int need, got;
631 int xs, ys, xe, ye;
632 int focusmin = 0;
634 xs = cv->c_xs;
635 ys = cv->c_ys;
636 xe = cv->c_xe;
637 ye = cv->c_ye;
638 cv = cv->c_slperp;
639 debug2("ResizeCanvas: %d,%d", xs, ys);
640 debug2(" %d,%d\n", xe, ye);
641 if (cv == 0)
642 return;
643 if (cv->c_slorient == SLICE_UNKN)
645 ASSERT(!cv->c_slnext && !cv->c_slperp);
646 cv->c_xs = xs;
647 cv->c_xe = xe;
648 cv->c_ys = ys;
649 cv->c_ye = ye;
650 cv->c_xoff = cv->c_xs;
651 cv->c_yoff = cv->c_ys;
652 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
653 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
654 return;
657 fcv = 0;
658 if (focusminwidth || focusminheight)
660 debug("searching for focus canvas\n");
661 cv2 = D_forecv;
662 while (cv2->c_slback)
664 if (cv2->c_slback == cv->c_slback)
666 fcv = cv2;
667 focusmin = cv->c_slorient == SLICE_VERT ? focusminheight : focusminwidth;
668 if (focusmin > 0)
669 focusmin--;
670 else if (focusmin < 0)
671 focusmin = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
672 debug1("found, focusmin=%d\n", focusmin);
674 cv2 = cv2->c_slback;
677 if (focusmin)
679 m = CountCanvas(cv) * 2;
680 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
681 nh -= m;
682 if (nh < 0)
683 nh = 0;
684 if (focusmin > nh)
685 focusmin = nh;
686 debug1("corrected to %d\n", focusmin);
689 /* pass 1: calculate weight sum */
690 for (cv2 = cv, wsum = 0; cv2; cv2 = cv2->c_slnext)
692 debug1(" weight %d\n", cv2->c_slweight);
693 wsum += cv2->c_slweight;
695 debug1("wsum = %d\n", wsum);
696 if (wsum == 0)
697 wsum = 1;
698 w = wsum;
700 /* pass 2: calculate need/excess space */
701 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
702 for (cv2 = cv, need = got = 0; cv2; cv2 = cv2->c_slnext)
704 m = cv2->c_slperp ? CountCanvasPerp(cv2) * 2 - 1 : 1;
705 if (cv2 == fcv)
706 m += focusmin;
707 hh = cv2->c_slweight ? nh * cv2->c_slweight / w : 0;
708 w -= cv2->c_slweight;
709 nh -= hh;
710 debug2(" should %d min %d\n", hh, m);
711 if (hh <= m + 1)
712 need += m + 1 - hh;
713 else
714 got += hh - m - 1;
716 debug2("need: %d, got %d\n", need, got);
717 if (need > got)
718 need = got;
720 /* pass 3: distribute space */
721 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
722 i = cv->c_slorient == SLICE_VERT ? ys : xs;
723 maxi = cv->c_slorient == SLICE_VERT ? ye : xe;
724 w = wsum;
725 for (; cv; cv = cvn)
727 cvn = cv->c_slnext;
728 if (i > maxi)
730 if (cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slprev->c_slperp && !cv->c_slprev->c_slprev)
732 cv->c_slprev->c_slorient = SLICE_UNKN;
733 if (!captionalways)
735 cv->c_slback->c_ye++;
736 cv->c_slprev->c_ye++;
739 SetCanvasWindow(cv, 0);
740 FreeCanvas(cv);
741 continue;
743 m = cv->c_slperp ? CountCanvasPerp(cv) * 2 - 1 : 1;
744 if (cv == fcv)
745 m += focusmin;
746 hh = cv->c_slweight ? nh * cv->c_slweight / w : 0;
747 w -= cv->c_slweight;
748 nh -= hh;
749 debug2(" should %d min %d\n", hh, m);
750 if (hh <= m + 1)
752 hh = m + 1;
753 debug1(" -> %d\n", hh);
755 else
757 int hx = need * (hh - m - 1) / got;
758 debug3(" -> %d - %d = %d\n", hh, hx, hh - hx);
759 got -= (hh - m - 1);
760 hh -= hx;
761 need -= hx;
762 debug2(" now need=%d got=%d\n", need, got);
764 ASSERT(hh >= m + 1);
765 /* hh is window size plus pation line */
766 if (i + hh > maxi + 2)
768 hh = maxi + 2 - i;
769 debug1(" not enough space, reducing to %d\n", hh);
771 if (i + hh == maxi + 1)
773 hh++;
774 debug(" incrementing as no other canvas will fit\n");
776 if (cv->c_slorient == SLICE_VERT)
778 cv->c_xs = xs;
779 cv->c_xe = xe;
780 cv->c_ys = i;
781 cv->c_ye = i + hh - 2;
782 cv->c_xoff = xs;
783 cv->c_yoff = i;
785 else
787 cv->c_xs = i;
788 cv->c_xe = i + hh - 2;
789 cv->c_ys = ys;
790 cv->c_ye = ye;
791 cv->c_xoff = i;
792 cv->c_yoff = ys;
794 cv->c_xoff = cv->c_xs;
795 cv->c_yoff = cv->c_ys;
796 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
797 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
798 if (cv->c_slperp)
800 ResizeCanvas(cv);
801 if (!cv->c_slperp->c_slnext)
803 debug("deleting perp node\n");
804 FreePerp(cv->c_slperp);
805 FreePerp(cv);
808 i += hh;
812 static struct canvas *
813 AddPerp(cv)
814 struct canvas *cv;
816 struct canvas *pcv;
817 debug("Creating new perp node\n");
819 if ((pcv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
820 return 0;
821 pcv->c_next = 0;
822 pcv->c_display = cv->c_display;
823 pcv->c_slnext = cv->c_slnext;
824 pcv->c_slprev = cv->c_slprev;
825 pcv->c_slperp = cv;
826 pcv->c_slback = cv->c_slback;
827 if (cv->c_slback && cv->c_slback->c_slperp == cv)
828 cv->c_slback->c_slperp = pcv;
829 pcv->c_slorient = cv->c_slorient;
830 pcv->c_xoff = 0;
831 pcv->c_yoff = 0;
832 pcv->c_xs = cv->c_xs;
833 pcv->c_xe = cv->c_xe;
834 pcv->c_ys = cv->c_ys;
835 pcv->c_ye = cv->c_ye;
836 if (pcv->c_slnext)
837 pcv->c_slnext->c_slprev = pcv;
838 if (pcv->c_slprev)
839 pcv->c_slprev->c_slnext = pcv;
840 pcv->c_slweight = cv->c_slweight;
841 CanvasInitBlank(pcv);
842 cv->c_slweight = 1;
843 cv->c_slnext = 0;
844 cv->c_slprev = 0;
845 cv->c_slperp = 0;
846 cv->c_slback = pcv;
847 cv->c_slorient = SLICE_UNKN;
848 return pcv;
851 static void
852 FreePerp(pcv)
853 struct canvas *pcv;
855 struct canvas *cv;
857 if (!pcv->c_slperp)
858 return;
859 cv = pcv->c_slperp;
860 cv->c_slprev = pcv->c_slprev;
861 if (cv->c_slprev)
862 cv->c_slprev->c_slnext = cv;
863 cv->c_slback = pcv->c_slback;
864 if (cv->c_slback && cv->c_slback->c_slperp == pcv)
865 cv->c_slback->c_slperp = cv;
866 cv->c_slorient = pcv->c_slorient;
867 cv->c_slweight = pcv->c_slweight;
868 while (cv->c_slnext)
870 cv = cv->c_slnext;
871 cv->c_slorient = pcv->c_slorient;
872 cv->c_slback = pcv->c_slback;
873 cv->c_slweight = pcv->c_slweight;
875 cv->c_slnext = pcv->c_slnext;
876 if (cv->c_slnext)
877 cv->c_slnext->c_slprev = cv;
878 free(pcv);
882 AddCanvas(orient)
883 int orient;
885 struct canvas *cv;
886 int xs, xe, ys, ye;
887 int h, num;
889 cv = D_forecv;
890 debug2("AddCanvas orient %d, forecv is %d\n", orient, cv->c_slorient);
892 if (cv->c_slorient != SLICE_UNKN && cv->c_slorient != orient)
893 if (!AddPerp(cv))
894 return -1;
896 cv = D_forecv;
897 xs = cv->c_slback->c_xs;
898 xe = cv->c_slback->c_xe;
899 ys = cv->c_slback->c_ys;
900 ye = cv->c_slback->c_ye;
901 if (!captionalways && cv == D_canvas.c_slperp && !cv->c_slnext)
902 ye--; /* need space for caption */
903 debug2("Adding Canvas to slice %d,%d ", xs, ys);
904 debug2("%d,%d\n", xe, ye);
906 num = CountCanvas(cv->c_slback->c_slperp) + 1;
907 debug1("Num = %d\n", num);
908 if (orient == SLICE_VERT)
909 h = ye - ys + 1;
910 else
911 h = xe - xs + 1;
913 h -= 2 * num - 1;
914 if (h < 0)
915 return -1; /* can't fit in */
917 if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
918 return -1;
920 D_forecv->c_slback->c_ye = ye; /* in case we modified it above */
921 D_forecv->c_slorient = orient; /* in case it was UNKN */
922 cv->c_slnext = D_forecv->c_slnext;
923 cv->c_slprev = D_forecv;
924 D_forecv->c_slnext = cv;
925 if (cv->c_slnext)
926 cv->c_slnext->c_slprev = cv;
927 cv->c_slorient = orient;
928 cv->c_slback = D_forecv->c_slback;
930 cv->c_xs = xs;
931 cv->c_xe = xe;
932 cv->c_ys = ys;
933 cv->c_ye = ye;
934 cv->c_xoff = 0;
935 cv->c_yoff = 0;
936 cv->c_display = display;
937 cv->c_vplist = 0;
938 cv->c_captev.type = EV_TIMEOUT;
939 cv->c_captev.data = (char *)cv;
940 cv->c_captev.handler = cv_winid_fn;
942 CanvasInitBlank(cv);
943 cv->c_lnext = 0;
945 cv->c_next = 0;
947 cv = cv->c_slback;
948 EqualizeCanvas(cv->c_slperp, 0);
949 ResizeCanvas(cv);
950 RecreateCanvasChain();
951 RethinkDisplayViewports();
952 ResizeLayersToCanvases();
953 return 0;
956 void
957 RemCanvas()
959 int xs, xe, ys, ye;
960 struct canvas *cv;
962 debug("RemCanvas\n");
963 cv = D_forecv;
964 if (cv->c_slorient == SLICE_UNKN)
965 return;
966 while (cv->c_slprev)
967 cv = cv->c_slprev;
968 if (!cv->c_slnext)
969 return;
970 if (!cv->c_slnext->c_slnext && cv->c_slback->c_slback)
972 /* two canvases in slice, kill perp node */
973 cv = D_forecv;
974 debug("deleting perp node\n");
975 FreePerp(cv->c_slprev ? cv->c_slprev : cv->c_slnext);
976 FreePerp(cv->c_slback);
978 xs = cv->c_slback->c_xs;
979 xe = cv->c_slback->c_xe;
980 ys = cv->c_slback->c_ys;
981 ye = cv->c_slback->c_ye;
982 /* free canvas */
983 cv = D_forecv;
984 D_forecv = cv->c_slprev;
985 if (!D_forecv)
986 D_forecv = cv->c_slnext;
987 FreeCanvas(cv);
989 cv = D_forecv;
990 while (D_forecv->c_slperp)
991 D_forecv = D_forecv->c_slperp;
993 /* if only one canvas left, set orient back to unknown */
994 if (!cv->c_slnext && !cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slperp)
996 cv->c_slorient = SLICE_UNKN;
997 if (!captionalways)
998 cv->c_slback->c_ye = ++ye; /* caption line no longer needed */
1000 cv = cv->c_slback;
1001 EqualizeCanvas(cv->c_slperp, 0);
1002 ResizeCanvas(cv);
1004 D_fore = Layer2Window(D_forecv->c_layer);
1005 flayer = D_forecv->c_layer;
1007 RecreateCanvasChain();
1008 RethinkDisplayViewports();
1009 ResizeLayersToCanvases();
1012 void
1013 OneCanvas()
1015 struct canvas *cv = D_forecv, *ocv = 0;
1017 if (cv->c_slprev)
1019 ocv = cv->c_slprev;
1020 cv->c_slprev->c_slnext = cv->c_slnext;
1022 if (cv->c_slnext)
1024 ocv = cv->c_slnext;
1025 cv->c_slnext->c_slprev = cv->c_slprev;
1027 if (!ocv)
1028 return;
1029 if (cv->c_slback && cv->c_slback->c_slperp == cv)
1030 cv->c_slback->c_slperp = ocv;
1031 cv->c_slorient = SLICE_UNKN;
1032 while (D_canvas.c_slperp)
1033 FreeCanvas(D_canvas.c_slperp);
1034 cv = D_forecv;
1035 D_canvas.c_slperp = cv;
1036 cv->c_slback = &D_canvas;
1037 cv->c_slnext = 0;
1038 cv->c_slprev = 0;
1039 ASSERT(!cv->c_slperp);
1040 if (!captionalways)
1041 D_canvas.c_ye++; /* caption line no longer needed */
1042 ResizeCanvas(&D_canvas);
1043 RecreateCanvasChain();
1044 RethinkDisplayViewports();
1045 ResizeLayersToCanvases();
1049 RethinkDisplayViewports()
1051 struct canvas *cv;
1052 struct viewport *vp, *vpn;
1054 /* free old viewports */
1055 for (cv = display->d_cvlist; cv; cv = cv->c_next)
1057 for (vp = cv->c_vplist; vp; vp = vpn)
1059 vp->v_canvas = 0;
1060 vpn = vp->v_next;
1061 bzero((char *)vp, sizeof(*vp));
1062 free(vp);
1064 cv->c_vplist = 0;
1066 display->d_vpxmin = -1;
1067 display->d_vpxmax = -1;
1069 for (cv = display->d_cvlist; cv; cv = cv->c_next)
1071 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1072 return -1;
1073 #ifdef HOLE
1074 vp->v_canvas = cv;
1075 vp->v_xs = cv->c_xs;
1076 vp->v_ys = (cv->c_ys + cv->c_ye) / 2;
1077 vp->v_xe = cv->c_xe;
1078 vp->v_ye = cv->c_ye;
1079 vp->v_xoff = cv->c_xoff;
1080 vp->v_yoff = cv->c_yoff;
1081 vp->v_next = cv->c_vplist;
1082 cv->c_vplist = vp;
1084 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1085 return -1;
1086 vp->v_canvas = cv;
1087 vp->v_xs = (cv->c_xs + cv->c_xe) / 2;
1088 vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
1089 vp->v_xe = cv->c_xe;
1090 vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
1091 vp->v_xoff = cv->c_xoff;
1092 vp->v_yoff = cv->c_yoff;
1093 vp->v_next = cv->c_vplist;
1094 cv->c_vplist = vp;
1096 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1097 return -1;
1098 vp->v_canvas = cv;
1099 vp->v_xs = cv->c_xs;
1100 vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
1101 vp->v_xe = (3 * cv->c_xs + cv->c_xe) / 4 - 1;
1102 vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
1103 vp->v_xoff = cv->c_xoff;
1104 vp->v_yoff = cv->c_yoff;
1105 vp->v_next = cv->c_vplist;
1106 cv->c_vplist = vp;
1108 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1109 return -1;
1110 vp->v_canvas = cv;
1111 vp->v_xs = cv->c_xs;
1112 vp->v_ys = cv->c_ys;
1113 vp->v_xe = cv->c_xe;
1114 vp->v_ye = (3 * cv->c_ys + cv->c_ye) / 4 - 1;
1115 vp->v_xoff = cv->c_xoff;
1116 vp->v_yoff = cv->c_yoff;
1117 vp->v_next = cv->c_vplist;
1118 cv->c_vplist = vp;
1119 #else
1120 vp->v_canvas = cv;
1121 vp->v_xs = cv->c_xs;
1122 vp->v_ys = cv->c_ys;
1123 vp->v_xe = cv->c_xe;
1124 vp->v_ye = cv->c_ye;
1125 vp->v_xoff = cv->c_xoff;
1126 vp->v_yoff = cv->c_yoff;
1127 vp->v_next = cv->c_vplist;
1128 cv->c_vplist = vp;
1129 #endif
1131 if (cv->c_xs < display->d_vpxmin || display->d_vpxmin == -1)
1132 display->d_vpxmin = cv->c_xs;
1133 if (cv->c_xe > display->d_vpxmax || display->d_vpxmax == -1)
1134 display->d_vpxmax = cv->c_xe;
1136 return 0;
1139 void
1140 RethinkViewportOffsets(cv)
1141 struct canvas *cv;
1143 struct viewport *vp;
1145 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1147 vp->v_xoff = cv->c_xoff;
1148 vp->v_yoff = cv->c_yoff;
1153 * if the adaptflag is on, we keep the size of this display, else
1154 * we may try to restore our old window sizes.
1156 void
1157 InitTerm(adapt)
1158 int adapt;
1160 ASSERT(display);
1161 ASSERT(D_tcinited);
1162 D_top = D_bot = -1;
1163 AddCStr(D_IS);
1164 AddCStr(D_TI);
1165 /* Check for toggle */
1166 if (D_IM && strcmp(D_IM, D_EI))
1167 AddCStr(D_EI);
1168 D_insert = 0;
1169 #ifdef MAPKEYS
1170 AddCStr(D_KS);
1171 AddCStr(D_CCS);
1172 #else
1173 /* Check for toggle */
1174 if (D_KS && strcmp(D_KS, D_KE))
1175 AddCStr(D_KE);
1176 if (D_CCS && strcmp(D_CCS, D_CCE))
1177 AddCStr(D_CCE);
1178 #endif
1179 D_keypad = 0;
1180 D_cursorkeys = 0;
1181 AddCStr(D_ME);
1182 AddCStr(D_EA);
1183 AddCStr(D_CE0);
1184 D_rend = mchar_null;
1185 D_atyp = 0;
1186 if (adapt == 0)
1187 ResizeDisplay(D_defwidth, D_defheight);
1188 ChangeScrollRegion(0, D_height - 1);
1189 D_x = D_y = 0;
1190 Flush();
1191 ClearAll();
1192 debug1("we %swant to adapt all our windows to the display\n",
1193 (adapt) ? "" : "don't ");
1194 /* In case the size was changed by a init sequence */
1195 CheckScreenSize((adapt) ? 2 : 0);
1198 void
1199 FinitTerm()
1201 ASSERT(display);
1202 #ifdef BLANKER_PRG
1203 KillBlanker();
1204 #endif
1205 if (D_tcinited)
1207 ResizeDisplay(D_defwidth, D_defheight);
1208 InsertMode(0);
1209 ChangeScrollRegion(0, D_height - 1);
1210 KeypadMode(0);
1211 CursorkeysMode(0);
1212 CursorVisibility(0);
1213 MouseMode(0);
1214 SetRendition(&mchar_null);
1215 SetFlow(FLOW_NOW);
1216 #ifdef MAPKEYS
1217 AddCStr(D_KE);
1218 AddCStr(D_CCE);
1219 #endif
1220 if (D_hstatus)
1221 ShowHStatus((char *)0);
1222 #ifdef RXVT_OSC
1223 ClearAllXtermOSC();
1224 #endif
1225 D_x = D_y = -1;
1226 GotoPos(0, D_height - 1);
1227 AddChar('\r');
1228 AddChar('\n');
1229 AddCStr(D_TE);
1231 Flush();
1235 static void
1236 INSERTCHAR(c)
1237 int c;
1239 ASSERT(display);
1240 if (!D_insert && D_x < D_width - 1)
1242 if (D_IC || D_CIC)
1244 if (D_IC)
1245 AddCStr(D_IC);
1246 else
1247 AddCStr2(D_CIC, 1);
1248 RAW_PUTCHAR(c);
1249 return;
1251 InsertMode(1);
1252 if (!D_insert)
1254 RefreshLine(D_y, D_x, D_width-1, 0);
1255 return;
1258 RAW_PUTCHAR(c);
1261 void
1262 PUTCHAR(c)
1263 int c;
1265 ASSERT(display);
1266 if (D_insert && D_x < D_width - 1)
1267 InsertMode(0);
1268 RAW_PUTCHAR(c);
1271 void
1272 PUTCHARLP(c)
1273 int c;
1275 if (D_x < D_width - 1)
1277 if (D_insert)
1278 InsertMode(0);
1279 RAW_PUTCHAR(c);
1280 return;
1282 if (D_CLP || D_y != D_bot)
1284 int y = D_y;
1285 RAW_PUTCHAR(c);
1286 if (D_AM && !D_CLP)
1287 GotoPos(D_width - 1, y);
1288 return;
1290 debug("PUTCHARLP: lp_missing!\n");
1291 D_lp_missing = 1;
1292 D_rend.image = c;
1293 D_lpchar = D_rend;
1294 #ifdef DW_CHARS
1295 /* XXX -> PutChar ? */
1296 if (D_mbcs)
1298 D_lpchar.mbcs = c;
1299 D_lpchar.image = D_mbcs;
1300 D_mbcs = 0;
1301 D_x--;
1303 #endif
1307 * RAW_PUTCHAR() is for all text that will be displayed.
1308 * NOTE: charset Nr. 0 has a conversion table, but c1, c2, ... don't.
1311 STATIC void
1312 RAW_PUTCHAR(c)
1313 int c;
1315 ASSERT(display);
1317 #ifdef FONT
1318 # ifdef UTF8
1319 if (D_encoding == UTF8)
1321 c = (c & 255) | (unsigned char)D_rend.font << 8;
1322 # ifdef DW_CHARS
1323 if (D_mbcs)
1325 c = D_mbcs;
1326 if (D_x == D_width)
1327 D_x += D_AM ? 1 : -1;
1328 D_mbcs = 0;
1330 else if (utf8_isdouble(c))
1332 D_mbcs = c;
1333 D_x++;
1334 return;
1336 # endif
1337 if (c < 32)
1339 AddCStr2(D_CS0, '0');
1340 AddChar(c + 0x5f);
1341 AddCStr(D_CE0);
1342 goto addedutf8;
1344 AddUtf8(c);
1345 goto addedutf8;
1347 # endif
1348 # ifdef DW_CHARS
1349 if (is_dw_font(D_rend.font))
1351 int t = c;
1352 if (D_mbcs == 0)
1354 D_mbcs = c;
1355 D_x++;
1356 return;
1358 D_x--;
1359 if (D_x == D_width - 1)
1360 D_x += D_AM ? 1 : -1;
1361 c = D_mbcs;
1362 D_mbcs = t;
1364 # endif
1365 # if defined(ENCODINGS) && defined(DW_CHARS)
1366 if (D_encoding)
1367 c = PrepareEncodedChar(c);
1368 # endif
1369 # ifdef DW_CHARS
1370 kanjiloop:
1371 # endif
1372 if (D_xtable && D_xtable[(int)(unsigned char)D_rend.font] && D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c])
1373 AddStr(D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c]);
1374 else
1375 AddChar(D_rend.font != '0' ? c : D_c0_tab[(int)(unsigned char)c]);
1376 #else /* FONT */
1377 AddChar(c);
1378 #endif /* FONT */
1380 #ifdef UTF8
1381 addedutf8:
1382 #endif
1383 if (++D_x >= D_width)
1385 if (D_AM == 0)
1386 D_x = D_width - 1;
1387 else if (!D_CLP || D_x > D_width)
1389 D_x -= D_width;
1390 if (D_y < D_height-1 && D_y != D_bot)
1391 D_y++;
1394 #ifdef DW_CHARS
1395 if (D_mbcs)
1397 c = D_mbcs;
1398 D_mbcs = 0;
1399 goto kanjiloop;
1401 #endif
1404 static int
1405 DoAddChar(c)
1406 int c;
1408 /* this is for ESC-sequences only (AddChar is a macro) */
1409 AddChar(c);
1410 return c;
1413 void
1414 AddCStr(s)
1415 char *s;
1417 if (display && s && *s)
1419 ospeed = D_dospeed;
1420 tputs(s, 1, DoAddChar);
1424 void
1425 AddCStr2(s, c)
1426 char *s;
1427 int c;
1429 if (display && s && *s)
1431 ospeed = D_dospeed;
1432 tputs(tgoto(s, 0, c), 1, DoAddChar);
1437 /* Insert mode is a toggle on some terminals, so we need this hack:
1439 void
1440 InsertMode(on)
1441 int on;
1443 if (display && on != D_insert && D_IM)
1445 D_insert = on;
1446 if (on)
1447 AddCStr(D_IM);
1448 else
1449 AddCStr(D_EI);
1453 /* ...and maybe keypad application mode is a toggle, too:
1455 void
1456 KeypadMode(on)
1457 int on;
1459 #ifdef MAPKEYS
1460 if (display)
1461 D_keypad = on;
1462 #else
1463 if (display && D_keypad != on && D_KS)
1465 D_keypad = on;
1466 if (on)
1467 AddCStr(D_KS);
1468 else
1469 AddCStr(D_KE);
1471 #endif
1474 void
1475 CursorkeysMode(on)
1476 int on;
1478 #ifdef MAPKEYS
1479 if (display)
1480 D_cursorkeys = on;
1481 #else
1482 if (display && D_cursorkeys != on && D_CCS)
1484 D_cursorkeys = on;
1485 if (on)
1486 AddCStr(D_CCS);
1487 else
1488 AddCStr(D_CCE);
1490 #endif
1493 void
1494 ReverseVideo(on)
1495 int on;
1497 if (display && D_revvid != on && D_CVR)
1499 D_revvid = on;
1500 if (D_revvid)
1501 AddCStr(D_CVR);
1502 else
1503 AddCStr(D_CVN);
1507 void
1508 CursorVisibility(v)
1509 int v;
1511 if (display && D_curvis != v)
1513 if (D_curvis)
1514 AddCStr(D_VE); /* do this always, just to be safe */
1515 D_curvis = 0;
1516 if (v == -1 && D_VI)
1517 AddCStr(D_VI);
1518 else if (v == 1 && D_VS)
1519 AddCStr(D_VS);
1520 else
1521 return;
1522 D_curvis = v;
1526 void
1527 MouseMode(mode)
1528 int mode;
1530 if (display && D_mouse != mode)
1532 char mousebuf[20];
1533 if (!D_CXT)
1534 return;
1535 if (D_mouse)
1537 sprintf(mousebuf, "\033[?%dl", D_mouse);
1538 AddStr(mousebuf);
1540 if (mode)
1542 sprintf(mousebuf, "\033[?%dh", mode);
1543 AddStr(mousebuf);
1545 D_mouse = mode;
1549 static int StrCost;
1551 /* ARGSUSED */
1552 static int
1553 CountChars(c)
1554 int c;
1556 StrCost++;
1557 return c;
1561 CalcCost(s)
1562 register char *s;
1564 ASSERT(display);
1565 if (s)
1567 StrCost = 0;
1568 ospeed = D_dospeed;
1569 tputs(s, 1, CountChars);
1570 return StrCost;
1572 else
1573 return EXPENSIVE;
1576 static int
1577 CallRewrite(y, xs, xe, doit)
1578 int y, xs, xe, doit;
1580 struct canvas *cv, *cvlist, *cvlnext;
1581 struct viewport *vp;
1582 struct layer *oldflayer;
1583 int cost;
1585 debug3("CallRewrite %d %d %d\n", y, xs, xe);
1586 ASSERT(display);
1587 ASSERT(xe >= xs);
1589 vp = 0;
1590 for (cv = D_cvlist; cv; cv = cv->c_next)
1592 if (y < cv->c_ys || y > cv->c_ye || xe < cv->c_xs || xs > cv->c_xe)
1593 continue;
1594 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1595 if (y >= vp->v_ys && y <= vp->v_ye && xe >= vp->v_xs && xs <= vp->v_xe)
1596 break;
1597 if (vp)
1598 break;
1600 if (doit)
1602 oldflayer = flayer;
1603 flayer = cv->c_layer;
1604 cvlist = flayer->l_cvlist;
1605 cvlnext = cv->c_lnext;
1606 flayer->l_cvlist = cv;
1607 cv->c_lnext = 0;
1608 LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 1);
1609 flayer->l_cvlist = cvlist;
1610 cv->c_lnext = cvlnext;
1611 flayer = oldflayer;
1612 return 0;
1614 if (cv == 0 || cv->c_layer == 0)
1615 return EXPENSIVE; /* not found or nothing on it */
1616 if (xs < vp->v_xs || xe > vp->v_xe)
1617 return EXPENSIVE; /* crosses viewport boundaries */
1618 if (y - vp->v_yoff < 0 || y - vp->v_yoff >= cv->c_layer->l_height)
1619 return EXPENSIVE; /* line not on layer */
1620 if (xs - vp->v_xoff < 0 || xe - vp->v_xoff >= cv->c_layer->l_width)
1621 return EXPENSIVE; /* line not on layer */
1622 #ifdef UTF8
1623 if (D_encoding == UTF8)
1624 D_rend.font = 0;
1625 #endif
1626 oldflayer = flayer;
1627 flayer = cv->c_layer;
1628 debug3("Calling Rewrite %d %d %d\n", y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff);
1629 cost = LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 0);
1630 flayer = oldflayer;
1631 if (D_insert)
1632 cost += D_EIcost + D_IMcost;
1633 return cost;
1637 void
1638 GotoPos(x2, y2)
1639 int x2, y2;
1641 register int dy, dx, x1, y1;
1642 register int costx, costy;
1643 register int m;
1644 register char *s;
1645 int CMcost;
1646 enum move_t xm = M_NONE, ym = M_NONE;
1648 if (!display)
1649 return;
1651 x1 = D_x;
1652 y1 = D_y;
1654 if (x1 == D_width)
1656 if (D_CLP && D_AM)
1657 x1 = -1; /* don't know how the terminal treats this */
1658 else
1659 x1--;
1661 if (x2 == D_width)
1662 x2--;
1663 dx = x2 - x1;
1664 dy = y2 - y1;
1665 if (dy == 0 && dx == 0)
1666 return;
1667 debug2("GotoPos (%d,%d)", x1, y1);
1668 debug2(" -> (%d,%d)\n", x2, y2);
1669 if (!D_MS) /* Safe to move ? */
1670 SetRendition(&mchar_null);
1671 if (y1 < 0 /* don't know the y position */
1672 || (y2 > D_bot && y1 <= D_bot) /* have to cross border */
1673 || (y2 < D_top && y1 >= D_top)) /* of scrollregion ? */
1675 DoCM:
1676 if (D_HO && !x2 && !y2)
1677 AddCStr(D_HO);
1678 else
1679 AddCStr(tgoto(D_CM, x2, y2));
1680 D_x = x2;
1681 D_y = y2;
1682 return;
1685 /* some scrollregion implementations don't allow movements
1686 * away from the region. sigh.
1688 if ((y1 > D_bot && y2 > y1) || (y1 < D_top && y2 < y1))
1689 goto DoCM;
1691 /* Calculate CMcost */
1692 if (D_HO && !x2 && !y2)
1693 s = D_HO;
1694 else
1695 s = tgoto(D_CM, x2, y2);
1696 CMcost = CalcCost(s);
1698 /* Calculate the cost to move the cursor to the right x position */
1699 costx = EXPENSIVE;
1700 if (x1 >= 0) /* relativ x positioning only if we know where we are */
1702 if (dx > 0)
1704 if (D_CRI && (dx > 1 || !D_ND))
1706 costx = CalcCost(tgoto(D_CRI, 0, dx));
1707 xm = M_CRI;
1709 if ((m = D_NDcost * dx) < costx)
1711 costx = m;
1712 xm = M_RI;
1714 /* Speedup: dx <= LayRewrite() */
1715 if (dx < costx && (m = CallRewrite(y1, x1, x2 - 1, 0)) < costx)
1717 costx = m;
1718 xm = M_RW;
1721 else if (dx < 0)
1723 if (D_CLE && (dx < -1 || !D_BC))
1725 costx = CalcCost(tgoto(D_CLE, 0, -dx));
1726 xm = M_CLE;
1728 if ((m = -dx * D_LEcost) < costx)
1730 costx = m;
1731 xm = M_LE;
1734 else
1735 costx = 0;
1737 /* Speedup: LayRewrite() >= x2 */
1738 if (x2 + D_CRcost < costx && (m = (x2 ? CallRewrite(y1, 0, x2 - 1, 0) : 0) + D_CRcost) < costx)
1740 costx = m;
1741 xm = M_CR;
1744 /* Check if it is already cheaper to do CM */
1745 if (costx >= CMcost)
1746 goto DoCM;
1748 /* Calculate the cost to move the cursor to the right y position */
1749 costy = EXPENSIVE;
1750 if (dy > 0)
1752 if (D_CDO && dy > 1) /* DO & NL are always != 0 */
1754 costy = CalcCost(tgoto(D_CDO, 0, dy));
1755 ym = M_CDO;
1757 if ((m = dy * ((x2 == 0) ? D_NLcost : D_DOcost)) < costy)
1759 costy = m;
1760 ym = M_DO;
1763 else if (dy < 0)
1765 if (D_CUP && (dy < -1 || !D_UP))
1767 costy = CalcCost(tgoto(D_CUP, 0, -dy));
1768 ym = M_CUP;
1770 if ((m = -dy * D_UPcost) < costy)
1772 costy = m;
1773 ym = M_UP;
1776 else
1777 costy = 0;
1779 /* Finally check if it is cheaper to do CM */
1780 if (costx + costy >= CMcost)
1781 goto DoCM;
1783 switch (xm)
1785 case M_LE:
1786 while (dx++ < 0)
1787 AddCStr(D_BC);
1788 break;
1789 case M_CLE:
1790 AddCStr2(D_CLE, -dx);
1791 break;
1792 case M_RI:
1793 while (dx-- > 0)
1794 AddCStr(D_ND);
1795 break;
1796 case M_CRI:
1797 AddCStr2(D_CRI, dx);
1798 break;
1799 case M_CR:
1800 AddCStr(D_CR);
1801 D_x = 0;
1802 x1 = 0;
1803 /* FALLTHROUGH */
1804 case M_RW:
1805 if (x1 < x2)
1806 (void) CallRewrite(y1, x1, x2 - 1, 1);
1807 break;
1808 default:
1809 break;
1812 switch (ym)
1814 case M_UP:
1815 while (dy++ < 0)
1816 AddCStr(D_UP);
1817 break;
1818 case M_CUP:
1819 AddCStr2(D_CUP, -dy);
1820 break;
1821 case M_DO:
1822 s = (x2 == 0) ? D_NL : D_DO;
1823 while (dy-- > 0)
1824 AddCStr(s);
1825 break;
1826 case M_CDO:
1827 AddCStr2(D_CDO, dy);
1828 break;
1829 default:
1830 break;
1832 D_x = x2;
1833 D_y = y2;
1836 void
1837 ClearAll()
1839 ASSERT(display);
1840 ClearArea(0, 0, 0, D_width - 1, D_width - 1, D_height - 1, 0, 0);
1843 void
1844 ClearArea(x1, y1, xs, xe, x2, y2, bce, uselayfn)
1845 int x1, y1, xs, xe, x2, y2, bce, uselayfn;
1847 int y, xxe;
1848 struct canvas *cv;
1849 struct viewport *vp;
1851 debug2("Clear %d,%d", x1, y1);
1852 debug2(" %d-%d", xs, xe);
1853 debug2(" %d,%d", x2, y2);
1854 debug2(" uselayfn=%d bce=%d\n", uselayfn, bce);
1855 ASSERT(display);
1856 if (x1 == D_width)
1857 x1--;
1858 if (x2 == D_width)
1859 x2--;
1860 if (xs == -1)
1861 xs = x1;
1862 if (xe == -1)
1863 xe = x2;
1864 if (D_UT) /* Safe to erase ? */
1865 SetRendition(&mchar_null);
1866 #ifdef COLOR
1867 if (D_BE)
1868 SetBackColor(bce);
1869 #endif
1870 if (D_lp_missing && y1 <= D_bot && xe >= D_width - 1)
1872 if (y2 > D_bot || (y2 == D_bot && x2 >= D_width - 1))
1873 D_lp_missing = 0;
1875 if (x2 == D_width - 1 && (xs == 0 || y1 == y2) && xe == D_width - 1 && y2 == D_height - 1 && (!bce || D_BE))
1877 #ifdef AUTO_NUKE
1878 if (x1 == 0 && y1 == 0 && D_auto_nuke)
1879 NukePending();
1880 #endif
1881 if (x1 == 0 && y1 == 0 && D_CL)
1883 AddCStr(D_CL);
1884 D_y = D_x = 0;
1885 return;
1888 * Workaround a hp700/22 terminal bug. Do not use CD where CE
1889 * is also appropriate.
1891 if (D_CD && (y1 < y2 || !D_CE))
1893 GotoPos(x1, y1);
1894 AddCStr(D_CD);
1895 return;
1898 if (x1 == 0 && xs == 0 && (xe == D_width - 1 || y1 == y2) && y1 == 0 && D_CCD && (!bce || D_BE))
1900 GotoPos(x1, y1);
1901 AddCStr(D_CCD);
1902 return;
1904 xxe = xe;
1905 for (y = y1; y <= y2; y++, x1 = xs)
1907 if (y == y2)
1908 xxe = x2;
1909 if (x1 == 0 && D_CB && (xxe != D_width - 1 || (D_x == xxe && D_y == y)) && (!bce || D_BE))
1911 GotoPos(xxe, y);
1912 AddCStr(D_CB);
1913 continue;
1915 if (xxe == D_width - 1 && D_CE && (!bce || D_BE))
1917 GotoPos(x1, y);
1918 AddCStr(D_CE);
1919 continue;
1921 if (uselayfn)
1923 vp = 0;
1924 for (cv = D_cvlist; cv; cv = cv->c_next)
1926 if (y < cv->c_ys || y > cv->c_ye || xxe < cv->c_xs || x1 > cv->c_xe)
1927 continue;
1928 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1929 if (y >= vp->v_ys && y <= vp->v_ye && xxe >= vp->v_xs && x1 <= vp->v_xe)
1930 break;
1931 if (vp)
1932 break;
1934 if (cv && cv->c_layer && x1 >= vp->v_xs && xxe <= vp->v_xe &&
1935 y - vp->v_yoff >= 0 && y - vp->v_yoff < cv->c_layer->l_height &&
1936 xxe - vp->v_xoff >= 0 && x1 - vp->v_xoff < cv->c_layer->l_width)
1938 struct layer *oldflayer = flayer;
1939 struct canvas *cvlist, *cvlnext;
1940 flayer = cv->c_layer;
1941 cvlist = flayer->l_cvlist;
1942 cvlnext = cv->c_lnext;
1943 flayer->l_cvlist = cv;
1944 cv->c_lnext = 0;
1945 LayClearLine(y - vp->v_yoff, x1 - vp->v_xoff, xxe - vp->v_xoff, bce);
1946 flayer->l_cvlist = cvlist;
1947 cv->c_lnext = cvlnext;
1948 flayer = oldflayer;
1949 continue;
1952 ClearLine((struct mline *)0, y, x1, xxe, bce);
1958 * if cur_only > 0, we only redisplay current line, as a full refresh is
1959 * too expensive over a low baud line.
1961 void
1962 Redisplay(cur_only)
1963 int cur_only;
1965 ASSERT(display);
1967 /* XXX do em all? */
1968 InsertMode(0);
1969 ChangeScrollRegion(0, D_height - 1);
1970 KeypadMode(0);
1971 CursorkeysMode(0);
1972 CursorVisibility(0);
1973 MouseMode(0);
1974 SetRendition(&mchar_null);
1975 SetFlow(FLOW_NOW);
1977 ClearAll();
1978 #ifdef RXVT_OSC
1979 RefreshXtermOSC();
1980 #endif
1981 if (cur_only > 0 && D_fore)
1982 RefreshArea(0, D_fore->w_y, D_width - 1, D_fore->w_y, 1);
1983 else
1984 RefreshAll(1);
1985 RefreshHStatus();
1986 CV_CALL(D_forecv, LayRestore();LaySetCursor());
1989 void
1990 RedisplayDisplays(cur_only)
1991 int cur_only;
1993 struct display *olddisplay = display;
1994 for (display = displays; display; display = display->d_next)
1995 Redisplay(cur_only);
1996 display = olddisplay;
2000 /* XXX: use oml! */
2001 void
2002 ScrollH(y, xs, xe, n, bce, oml)
2003 int y, xs, xe, n, bce;
2004 struct mline *oml;
2006 int i;
2008 if (n == 0)
2009 return;
2010 if (xe != D_width - 1)
2012 RefreshLine(y, xs, xe, 0);
2013 /* UpdateLine(oml, y, xs, xe); */
2014 return;
2016 GotoPos(xs, y);
2017 if (D_UT)
2018 SetRendition(&mchar_null);
2019 #ifdef COLOR
2020 if (D_BE)
2021 SetBackColor(bce);
2022 #endif
2023 if (n > 0)
2025 if (n >= xe - xs + 1)
2026 n = xe - xs + 1;
2027 if (D_CDC && !(n == 1 && D_DC))
2028 AddCStr2(D_CDC, n);
2029 else if (D_DC)
2031 for (i = n; i--; )
2032 AddCStr(D_DC);
2034 else
2036 RefreshLine(y, xs, xe, 0);
2037 /* UpdateLine(oml, y, xs, xe); */
2038 return;
2041 else
2043 if (-n >= xe - xs + 1)
2044 n = -(xe - xs + 1);
2045 if (!D_insert)
2047 if (D_CIC && !(n == -1 && D_IC))
2048 AddCStr2(D_CIC, -n);
2049 else if (D_IC)
2051 for (i = -n; i--; )
2052 AddCStr(D_IC);
2054 else if (D_IM)
2056 InsertMode(1);
2057 SetRendition(&mchar_null);
2058 #ifdef COLOR
2059 SetBackColor(bce);
2060 #endif
2061 for (i = -n; i--; )
2062 INSERTCHAR(' ');
2063 bce = 0; /* all done */
2065 else
2067 /* UpdateLine(oml, y, xs, xe); */
2068 RefreshLine(y, xs, xe, 0);
2069 return;
2072 else
2074 SetRendition(&mchar_null);
2075 #ifdef COLOR
2076 SetBackColor(bce);
2077 #endif
2078 for (i = -n; i--; )
2079 INSERTCHAR(' ');
2080 bce = 0; /* all done */
2083 if (bce && !D_BE)
2085 if (n > 0)
2086 ClearLine((struct mline *)0, y, xe - n + 1, xe, bce);
2087 else
2088 ClearLine((struct mline *)0, y, xs, xs - n - 1, bce);
2090 if (D_lp_missing && y == D_bot)
2092 if (n > 0)
2093 WriteLP(D_width - 1 - n, y);
2094 D_lp_missing = 0;
2098 void
2099 ScrollV(xs, ys, xe, ye, n, bce)
2100 int xs, ys, xe, ye, n, bce;
2102 int i;
2103 int up;
2104 int oldtop, oldbot;
2105 int alok, dlok, aldlfaster;
2106 int missy = 0;
2108 ASSERT(display);
2109 if (n == 0)
2110 return;
2111 if (n >= ye - ys + 1 || -n >= ye - ys + 1)
2113 ClearArea(xs, ys, xs, xe, xe, ye, bce, 0);
2114 return;
2116 if (xs > D_vpxmin || xe < D_vpxmax)
2118 RefreshArea(xs, ys, xe, ye, 0);
2119 return;
2122 if (D_lp_missing)
2124 if (D_bot > ye || D_bot < ys)
2125 missy = D_bot;
2126 else
2128 missy = D_bot - n;
2129 if (missy > ye || missy < ys)
2130 D_lp_missing = 0;
2134 up = 1;
2135 if (n < 0)
2137 up = 0;
2138 n = -n;
2140 if (n >= ye - ys + 1)
2141 n = ye - ys + 1;
2143 oldtop = D_top;
2144 oldbot = D_bot;
2145 if (ys < D_top || D_bot != ye)
2146 ChangeScrollRegion(ys, ye);
2147 alok = (D_AL || D_CAL || (ys >= D_top && ye == D_bot && up));
2148 dlok = (D_DL || D_CDL || (ys >= D_top && ye == D_bot && !up));
2149 if (D_top != ys && !(alok && dlok))
2150 ChangeScrollRegion(ys, ye);
2152 if (D_lp_missing &&
2153 (oldbot != D_bot ||
2154 (oldbot == D_bot && up && D_top == ys && D_bot == ye)))
2156 WriteLP(D_width - 1, oldbot);
2157 if (oldbot == D_bot) /* have scrolled */
2159 if (--n == 0)
2161 /* XXX
2162 ChangeScrollRegion(oldtop, oldbot);
2164 if (bce && !D_BE)
2165 ClearLine((struct mline *)0, ye, xs, xe, bce);
2166 return;
2171 if (D_UT)
2172 SetRendition(&mchar_null);
2173 #ifdef COLOR
2174 if (D_BE)
2175 SetBackColor(bce);
2176 #endif
2178 aldlfaster = (n > 1 && ys >= D_top && ye == D_bot && ((up && D_CDL) || (!up && D_CAL)));
2180 if ((up || D_SR) && D_top == ys && D_bot == ye && !aldlfaster)
2182 if (up)
2184 GotoPos(0, ye);
2185 for(i = n; i-- > 0; )
2186 AddCStr(D_NL); /* was SF, I think NL is faster */
2188 else
2190 GotoPos(0, ys);
2191 for(i = n; i-- > 0; )
2192 AddCStr(D_SR);
2195 else if (alok && dlok)
2197 if (up || ye != D_bot)
2199 GotoPos(0, up ? ys : ye+1-n);
2200 if (D_CDL && !(n == 1 && D_DL))
2201 AddCStr2(D_CDL, n);
2202 else
2203 for(i = n; i--; )
2204 AddCStr(D_DL);
2206 if (!up || ye != D_bot)
2208 GotoPos(0, up ? ye+1-n : ys);
2209 if (D_CAL && !(n == 1 && D_AL))
2210 AddCStr2(D_CAL, n);
2211 else
2212 for(i = n; i--; )
2213 AddCStr(D_AL);
2216 else
2218 RefreshArea(xs, ys, xe, ye, 0);
2219 return;
2221 if (bce && !D_BE)
2223 if (up)
2224 ClearArea(xs, ye - n + 1, xs, xe, xe, ye, bce, 0);
2225 else
2226 ClearArea(xs, ys, xs, xe, xe, ys + n - 1, bce, 0);
2228 if (D_lp_missing && missy != D_bot)
2229 WriteLP(D_width - 1, missy);
2230 /* XXX
2231 ChangeScrollRegion(oldtop, oldbot);
2232 if (D_lp_missing && missy != D_bot)
2233 WriteLP(D_width - 1, missy);
2237 void
2238 SetAttr(new)
2239 register int new;
2241 register int i, j, old, typ;
2243 if (!display || (old = D_rend.attr) == new)
2244 return;
2245 #ifdef COLORS16
2246 D_col16change = (old ^ new) & (A_BFG | A_BBG);
2247 new ^= D_col16change;
2248 if (old == new)
2249 return;
2250 #endif
2251 #if defined(TERMINFO) && defined(USE_SGR)
2252 if (D_SA)
2254 char *tparm();
2255 SetFont(ASCII);
2256 ospeed = D_dospeed;
2257 tputs(tparm(D_SA, new & A_SO, new & A_US, new & A_RV, new & A_BL,
2258 new & A_DI, new & A_BD, 0 , 0 ,
2259 0), 1, DoAddChar);
2260 D_rend.attr = new;
2261 D_atyp = 0;
2262 # ifdef COLOR
2263 if (D_hascolor)
2264 rend_setdefault(&D_rend);
2265 # endif
2266 return;
2268 #endif
2269 D_rend.attr = new;
2270 typ = D_atyp;
2271 if ((new & old) != old)
2273 if ((typ & ATYP_U))
2274 AddCStr(D_UE);
2275 if ((typ & ATYP_S))
2276 AddCStr(D_SE);
2277 if ((typ & ATYP_M))
2279 AddCStr(D_ME);
2280 #ifdef COLOR
2281 /* ansi attrib handling: \E[m resets color, too */
2282 if (D_hascolor)
2283 rend_setdefault(&D_rend);
2284 #endif
2285 #ifdef FONT
2286 if (!D_CG0)
2288 /* D_ME may also reset the alternate charset */
2289 D_rend.font = 0;
2290 # ifdef ENCODINGS
2291 D_realfont = 0;
2292 # endif
2294 #endif
2296 old = 0;
2297 typ = 0;
2299 old ^= new;
2300 for (i = 0, j = 1; old && i < NATTR; i++, j <<= 1)
2302 if ((old & j) == 0)
2303 continue;
2304 old ^= j;
2305 if (D_attrtab[i])
2307 AddCStr(D_attrtab[i]);
2308 typ |= D_attrtyp[i];
2311 D_atyp = typ;
2314 #ifdef FONT
2315 void
2316 SetFont(new)
2317 int new;
2319 int old = D_rend.font;
2320 if (!display || old == new)
2321 return;
2322 D_rend.font = new;
2323 #ifdef ENCODINGS
2324 if (D_encoding && CanEncodeFont(D_encoding, new))
2325 return;
2326 if (new == D_realfont)
2327 return;
2328 D_realfont = new;
2329 #endif
2330 if (D_xtable && D_xtable[(int)(unsigned char)new] &&
2331 D_xtable[(int)(unsigned char)new][256])
2333 AddCStr(D_xtable[(int)(unsigned char)new][256]);
2334 return;
2337 if (!D_CG0 && new != '0')
2339 new = ASCII;
2340 if (old == new)
2341 return;
2344 if (new == ASCII)
2345 AddCStr(D_CE0);
2346 #ifdef DW_CHARS
2347 else if (new < ' ')
2349 AddStr("\033$");
2350 if (new > 2)
2351 AddChar('(');
2352 AddChar(new + '@');
2354 #endif
2355 else
2356 AddCStr2(D_CS0, new);
2358 #endif
2360 #ifdef COLOR
2363 color256to16(jj)
2364 int jj;
2366 int min, max;
2367 int r, g, b;
2369 if (jj >= 232)
2371 jj = (jj - 232) / 6;
2372 jj = (jj & 1) << 3 | (jj & 2 ? 7 : 0);
2374 else if (jj >= 16)
2376 jj -= 16;
2377 r = jj / 36;
2378 g = (jj / 6) % 6;
2379 b = jj % 6;
2380 min = r < g ? (r < b ? r : b) : (g < b ? g : b);
2381 max = r > g ? (r > b ? r : b) : (g > b ? g : b);
2382 if (min == max)
2383 jj = ((max + 1) & 2) << 2 | ((max + 1) & 4 ? 7 : 0);
2384 else
2385 jj = (b - min) / (max - min) << 2 | (g - min) / (max - min) << 1 | (r -
2386 min) / (max - min) | (max > 3 ? 8 : 0);
2388 return jj;
2391 #ifdef COLORS256
2393 color256to88(jj)
2394 int jj;
2396 int r, g, b;
2398 if (jj >= 232)
2399 return (jj - 232) / 3 + 80;
2400 if (jj >= 16)
2402 jj -= 16;
2403 r = jj / 36;
2404 g = (jj / 6) % 6;
2405 b = jj % 6;
2406 return ((r + 1) / 2) * 16 + ((g + 1) / 2) * 4 + ((b + 1) / 2) + 16;
2408 return jj;
2410 #endif
2412 void
2413 SetColor(f, b)
2414 int f, b;
2416 int of, ob;
2417 static unsigned char sftrans[8] = {0,4,2,6,1,5,3,7};
2419 if (!display)
2420 return;
2422 of = rend_getfg(&D_rend);
2423 ob = rend_getbg(&D_rend);
2425 #ifdef COLORS16
2426 /* intense default not invented yet */
2427 if (f == 0x100)
2428 f = 0;
2429 if (b == 0x100)
2430 b = 0;
2431 #endif
2432 debug2("SetColor %d %d", coli2e(of), coli2e(ob));
2433 debug2(" -> %d %d\n", coli2e(f), coli2e(b));
2434 debug2("(%d %d", of, ob);
2435 debug2(" -> %d %d)\n", f, b);
2437 if (!D_CAX && D_hascolor && ((f == 0 && f != of) || (b == 0 && b != ob)))
2439 if (D_OP)
2440 AddCStr(D_OP);
2441 else
2443 int oattr;
2444 oattr = D_rend.attr;
2445 AddCStr(D_ME ? D_ME : "\033[m");
2446 #ifdef FONT
2447 if (D_ME && !D_CG0)
2449 /* D_ME may also reset the alternate charset */
2450 D_rend.font = 0;
2451 # ifdef ENCODINGS
2452 D_realfont = 0;
2453 # endif
2455 #endif
2456 D_atyp = 0;
2457 D_rend.attr = 0;
2458 SetAttr(oattr);
2460 of = ob = 0;
2462 rend_setfg(&D_rend, f);
2463 rend_setbg(&D_rend, b);
2464 #ifdef COLORS16
2465 D_col16change = 0;
2466 #endif
2467 if (!D_hascolor)
2468 return;
2469 f = f ? coli2e(f) : -1;
2470 b = b ? coli2e(b) : -1;
2471 of = of ? coli2e(of) : -1;
2472 ob = ob ? coli2e(ob) : -1;
2473 #ifdef COLORS256
2474 if (f != of && f > 15 && D_CCO != 256)
2475 f = D_CCO == 88 && D_CAF ? color256to88(f) : color256to16(f);
2476 if (f != of && f > 15 && D_CAF)
2478 AddCStr2(D_CAF, f);
2479 of = f;
2481 if (b != ob && b > 15 && D_CCO != 256)
2482 b = D_CCO == 88 && D_CAB ? color256to88(b) : color256to16(b);
2483 if (b != ob && b > 15 && D_CAB)
2485 AddCStr2(D_CAB, b);
2486 ob = b;
2488 #endif
2489 if (f != of && f != (of | 8))
2491 if (f == -1)
2492 AddCStr("\033[39m"); /* works because AX is set */
2493 else if (D_CAF)
2494 AddCStr2(D_CAF, f & 7);
2495 else if (D_CSF)
2496 AddCStr2(D_CSF, sftrans[f & 7]);
2498 if (b != ob && b != (ob | 8))
2500 if (b == -1)
2501 AddCStr("\033[49m"); /* works because AX is set */
2502 else if (D_CAB)
2503 AddCStr2(D_CAB, b & 7);
2504 else if (D_CSB)
2505 AddCStr2(D_CSB, sftrans[b & 7]);
2507 #ifdef COLORS16
2508 if (f != of && D_CXT && (f & 8) != 0 && f != -1)
2510 # ifdef TERMINFO
2511 AddCStr2("\033[9%p1%dm", f & 7);
2512 # else
2513 AddCStr2("\033[9%dm", f & 7);
2514 # endif
2516 if (b != ob && D_CXT && (b & 8) != 0 && b != -1)
2518 # ifdef TERMINFO
2519 AddCStr2("\033[10%p1%dm", b & 7);
2520 # else
2521 AddCStr2("\033[10%dm", b & 7);
2522 # endif
2524 #endif
2527 static void
2528 SetBackColor(new)
2529 int new;
2531 if (!display)
2532 return;
2533 SetColor(rend_getfg(&D_rend), new);
2535 #endif /* COLOR */
2537 void
2538 SetRendition(mc)
2539 struct mchar *mc;
2541 if (!display)
2542 return;
2543 #ifdef COLOR
2544 if (nattr2color && D_hascolor && (mc->attr & nattr2color) != 0)
2546 static struct mchar mmc;
2547 int i;
2548 mmc = *mc;
2549 for (i = 0; i < 8; i++)
2550 if (attr2color[i] && (mc->attr & (1 << i)) != 0)
2552 if (mc->color == 0 && attr2color[i][3])
2553 ApplyAttrColor(attr2color[i][3], &mmc);
2554 else if ((mc->color & 0x0f) == 0 && attr2color[i][2])
2555 ApplyAttrColor(attr2color[i][2], &mmc);
2556 else if ((mc->color & 0xf0) == 0 && attr2color[i][1])
2557 ApplyAttrColor(attr2color[i][1], &mmc);
2558 else
2559 ApplyAttrColor(attr2color[i][0], &mmc);
2561 mc = &mmc;
2562 debug2("SetRendition: mapped to %02x %02x\n", (unsigned char)mc->attr, 0x99 - (unsigned char)mc->color);
2564 # ifdef COLORS16
2565 if (D_hascolor && D_CC8 && (mc->attr & (A_BFG|A_BBG)))
2567 int a = mc->attr;
2568 if ((mc->attr & A_BFG) && D_MD)
2569 a |= A_BD;
2570 if ((mc->attr & A_BBG) && D_MB)
2571 a |= A_BL;
2572 if (D_rend.attr != a)
2573 SetAttr(a);
2575 else
2576 # endif /* COLORS16 */
2577 #endif /* COLOR */
2578 if (D_rend.attr != mc->attr)
2579 SetAttr(mc->attr);
2581 #ifdef COLOR
2582 if (D_rend.color != mc->color
2583 # ifdef COLORS256
2584 || D_rend.colorx != mc->colorx
2585 # endif
2586 # ifdef COLORS16
2587 || D_col16change
2588 # endif
2590 SetColor(rend_getfg(mc), rend_getbg(mc));
2591 #endif
2592 #ifdef FONT
2593 if (D_rend.font != mc->font)
2594 SetFont(mc->font);
2595 #endif
2598 void
2599 SetRenditionMline(ml, x)
2600 struct mline *ml;
2601 int x;
2603 if (!display)
2604 return;
2605 #ifdef COLOR
2606 if (nattr2color && D_hascolor && (ml->attr[x] & nattr2color) != 0)
2608 struct mchar mc;
2609 copy_mline2mchar(&mc, ml, x);
2610 SetRendition(&mc);
2611 return;
2613 # ifdef COLORS16
2614 if (D_hascolor && D_CC8 && (ml->attr[x] & (A_BFG|A_BBG)))
2616 int a = ml->attr[x];
2617 if ((ml->attr[x] & A_BFG) && D_MD)
2618 a |= A_BD;
2619 if ((ml->attr[x] & A_BBG) && D_MB)
2620 a |= A_BL;
2621 if (D_rend.attr != a)
2622 SetAttr(a);
2624 else
2625 # endif /* COLORS16 */
2626 #endif /* COLOR */
2627 if (D_rend.attr != ml->attr[x])
2628 SetAttr(ml->attr[x]);
2629 #ifdef COLOR
2630 if (D_rend.color != ml->color[x]
2631 # ifdef COLORS256
2632 || D_rend.colorx != ml->colorx[x]
2633 # endif
2634 # ifdef COLORS16
2635 || D_col16change
2636 # endif
2639 struct mchar mc;
2640 copy_mline2mchar(&mc, ml, x);
2641 SetColor(rend_getfg(&mc), rend_getbg(&mc));
2643 #endif
2644 #ifdef FONT
2645 if (D_rend.font != ml->font[x])
2646 SetFont(ml->font[x]);
2647 #endif
2650 void
2651 MakeStatus(msg)
2652 char *msg;
2654 register char *s, *t;
2655 register int max;
2657 if (!display)
2658 return;
2660 if (D_blocked)
2661 return;
2662 if (!D_tcinited)
2664 debug("tc not inited, just writing msg\n");
2665 if (D_processinputdata)
2666 return; /* XXX: better */
2667 AddStr(msg);
2668 AddStr("\r\n");
2669 Flush();
2670 return;
2672 if (!use_hardstatus || !D_HS)
2674 max = D_width;
2675 if (D_CLP == 0)
2676 max--;
2678 else
2679 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2680 if (D_status)
2682 /* same message? */
2683 if (strcmp(msg, D_status_lastmsg) == 0)
2685 debug("same message - increase timeout");
2686 SetTimeout(&D_statusev, MsgWait);
2687 return;
2689 if (!D_status_bell)
2691 struct timeval now;
2692 int ti;
2693 gettimeofday(&now, NULL);
2694 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
2695 if (ti < MsgMinWait)
2696 DisplaySleep1000(MsgMinWait - ti, 0);
2698 RemoveStatus();
2700 for (s = t = msg; *s && t - msg < max; ++s)
2701 if (*s == BELL)
2702 AddCStr(D_BL);
2703 else if ((unsigned char)*s >= ' ' && *s != 0177)
2704 *t++ = *s;
2705 *t = '\0';
2706 if (t == msg)
2707 return;
2708 if (t - msg >= D_status_buflen)
2710 char *buf;
2711 if (D_status_lastmsg)
2712 buf = realloc(D_status_lastmsg, t - msg + 1);
2713 else
2714 buf = malloc(t - msg + 1);
2715 if (buf)
2717 D_status_lastmsg = buf;
2718 D_status_buflen = t - msg + 1;
2721 if (t - msg < D_status_buflen)
2722 strcpy(D_status_lastmsg, msg);
2723 D_status_len = t - msg;
2724 D_status_lastx = D_x;
2725 D_status_lasty = D_y;
2726 if (!use_hardstatus || D_has_hstatus == HSTATUS_IGNORE || D_has_hstatus == HSTATUS_MESSAGE)
2728 D_status = STATUS_ON_WIN;
2729 debug1("using STATLINE %d\n", STATLINE);
2730 GotoPos(0, STATLINE);
2731 SetRendition(&mchar_so);
2732 InsertMode(0);
2733 AddStr(msg);
2734 if (D_status_len < max)
2736 /* Wayne Davison: add extra space for readability */
2737 D_status_len++;
2738 SetRendition(&mchar_null);
2739 AddChar(' ');
2740 if (D_status_len < max)
2742 D_status_len++;
2743 AddChar(' ');
2744 AddChar('\b');
2746 AddChar('\b');
2748 D_x = -1;
2750 else
2752 D_status = STATUS_ON_HS;
2753 ShowHStatus(msg);
2755 Flush();
2756 if (!display)
2757 return;
2758 if (D_status == STATUS_ON_WIN)
2760 struct display *olddisplay = display;
2761 struct layer *oldflayer = flayer;
2763 ASSERT(D_obuffree == D_obuflen);
2764 /* this is copied over from RemoveStatus() */
2765 D_status = 0;
2766 GotoPos(0, STATLINE);
2767 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2768 GotoPos(D_status_lastx, D_status_lasty);
2769 flayer = D_forecv ? D_forecv->c_layer : 0;
2770 if (flayer)
2771 LaySetCursor();
2772 display = olddisplay;
2773 flayer = oldflayer;
2774 D_status_obuflen = D_obuflen;
2775 D_status_obuffree = D_obuffree;
2776 D_obuffree = D_obuflen = 0;
2777 D_status = STATUS_ON_WIN;
2779 gettimeofday(&D_status_time, NULL);
2780 SetTimeout(&D_statusev, MsgWait);
2781 evenq(&D_statusev);
2782 #ifdef HAVE_BRAILLE
2783 RefreshBraille(); /* let user see multiple Msg()s */
2784 #endif
2787 void
2788 RemoveStatus()
2790 struct display *olddisplay;
2791 struct layer *oldflayer;
2792 int where;
2794 if (!display)
2795 return;
2796 if (!(where = D_status))
2797 return;
2799 debug("RemoveStatus\n");
2800 if (D_status_obuffree >= 0)
2802 D_obuflen = D_status_obuflen;
2803 D_obuffree = D_status_obuffree;
2804 D_status_obuffree = -1;
2806 D_status = 0;
2807 D_status_bell = 0;
2808 evdeq(&D_statusev);
2809 olddisplay = display;
2810 oldflayer = flayer;
2811 if (where == STATUS_ON_WIN)
2813 if (captionalways || (D_canvas.c_slperp && D_canvas.c_slperp->c_slnext))
2815 GotoPos(0, STATLINE);
2816 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2817 GotoPos(D_status_lastx, D_status_lasty);
2820 else
2821 RefreshHStatus();
2822 flayer = D_forecv ? D_forecv->c_layer : 0;
2823 if (flayer)
2824 LaySetCursor();
2825 display = olddisplay;
2826 flayer = oldflayer;
2829 /* refresh the display's hstatus line */
2830 void
2831 ShowHStatus(str)
2832 char *str;
2834 int l, ox, oy, max;
2836 if (D_status == STATUS_ON_WIN && D_has_hstatus == HSTATUS_LASTLINE && STATLINE == D_height-1)
2837 return; /* sorry, in use */
2838 if (D_blocked)
2839 return;
2841 if (D_HS && D_has_hstatus == HSTATUS_HS)
2843 if (!D_hstatus && (str == 0 || *str == 0))
2844 return;
2845 debug("ShowHStatus: using HS\n");
2846 SetRendition(&mchar_null);
2847 InsertMode(0);
2848 if (D_hstatus)
2849 AddCStr(D_DS);
2850 D_hstatus = 0;
2851 if (str == 0 || *str == 0)
2852 return;
2853 AddCStr2(D_TS, 0);
2854 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2855 if ((int)strlen(str) > max)
2856 AddStrn(str, max);
2857 else
2858 AddStr(str);
2859 AddCStr(D_FS);
2860 D_hstatus = 1;
2862 else if (D_has_hstatus == HSTATUS_LASTLINE)
2864 debug("ShowHStatus: using last line\n");
2865 ox = D_x;
2866 oy = D_y;
2867 str = str ? str : "";
2868 l = strlen(str);
2869 if (l > D_width)
2870 l = D_width;
2871 GotoPos(0, D_height - 1);
2872 SetRendition(captionalways || D_cvlist == 0 || D_cvlist->c_next ? &mchar_null: &mchar_so);
2873 PutWinMsg(str, 0, l);
2874 if (!captionalways && D_cvlist && !D_cvlist->c_next)
2875 while (l++ < D_width)
2876 PUTCHARLP(' ');
2877 if (l < D_width)
2878 ClearArea(l, D_height - 1, l, D_width - 1, D_width - 1, D_height - 1, 0, 0);
2879 if (ox != -1 && oy != -1)
2880 GotoPos(ox, oy);
2881 D_hstatus = *str ? 1 : 0;
2882 SetRendition(&mchar_null);
2884 else if (str && *str && D_has_hstatus == HSTATUS_MESSAGE)
2886 debug("ShowHStatus: using message\n");
2887 Msg(0, "%s", str);
2893 * Refreshes the harstatus of the fore window. Shouldn't be here...
2895 void
2896 RefreshHStatus()
2898 char *buf;
2900 evdeq(&D_hstatusev);
2901 if (D_status == STATUS_ON_HS)
2902 return;
2903 buf = MakeWinMsgEv(hstatusstring, D_fore, '%', (D_HS && D_has_hstatus == HSTATUS_HS && D_WS > 0) ? D_WS : D_width - !D_CLP, &D_hstatusev, 0);
2904 if (buf && *buf)
2906 ShowHStatus(buf);
2907 if (D_has_hstatus != HSTATUS_IGNORE && D_hstatusev.timeout.tv_sec)
2908 evenq(&D_hstatusev);
2910 else
2911 ShowHStatus((char *)0);
2914 /*********************************************************************/
2916 * Here come the routines that refresh an arbitrary part of the screen.
2919 void
2920 RefreshAll(isblank)
2921 int isblank;
2923 struct canvas *cv;
2925 ASSERT(display);
2926 debug("Signalling full refresh!\n");
2927 for (cv = D_cvlist; cv; cv = cv->c_next)
2929 CV_CALL(cv, LayRedisplayLine(-1, -1, -1, isblank));
2930 display = cv->c_display; /* just in case! */
2932 RefreshArea(0, 0, D_width - 1, D_height - 1, isblank);
2935 void
2936 RefreshArea(xs, ys, xe, ye, isblank)
2937 int xs, ys, xe, ye, isblank;
2939 int y;
2940 ASSERT(display);
2941 debug2("Refresh Area: %d,%d", xs, ys);
2942 debug3(" - %d,%d (isblank=%d)\n", xe, ye, isblank);
2943 if (!isblank && xs == 0 && xe == D_width - 1 && ye == D_height - 1 && (ys == 0 || D_CD))
2945 ClearArea(xs, ys, xs, xe, xe, ye, 0, 0);
2946 isblank = 1;
2948 for (y = ys; y <= ye; y++)
2949 RefreshLine(y, xs, xe, isblank);
2952 void
2953 RefreshLine(y, from, to, isblank)
2954 int y, from, to, isblank;
2956 struct viewport *vp, *lvp;
2957 struct canvas *cv, *lcv, *cvlist, *cvlnext;
2958 struct layer *oldflayer;
2959 int xx, yy, l;
2960 char *buf;
2961 struct win *p;
2963 ASSERT(display);
2965 debug2("RefreshLine %d %d", y, from);
2966 debug2(" %d %d\n", to, isblank);
2968 if (D_status == STATUS_ON_WIN && y == STATLINE)
2970 if (to >= D_status_len)
2971 D_status_len = to + 1;
2972 return; /* can't refresh status */
2975 /* The following check makes plenty of sense. Unfortunately,
2976 vte-based terminals (notably gnome-terminal) experience a quirk
2977 that causes the final line not to update properly when it falls outside
2978 the scroll region; clearing the line with D_CE avoids the glitch,
2979 so we'll disable this perfectly sensible shortcut until such a time
2980 as widespread vte installations lack the glitch.
2982 See http://bugzilla.gnome.org/show_bug.cgi?id=542087 for current
2983 status of the VTE bug report, and
2984 https://savannah.gnu.org/bugs/index.php?23699 for the history from
2985 the Savannah BTS. */
2986 #if 0
2987 if (y == D_height - 1 && D_has_hstatus == HSTATUS_LASTLINE)
2989 RefreshHStatus();
2990 return;
2992 #endif
2994 if (isblank == 0 && D_CE && to == D_width - 1 && from < to)
2996 GotoPos(from, y);
2997 if (D_UT || D_BE)
2998 SetRendition(&mchar_null);
2999 AddCStr(D_CE);
3000 isblank = 1;
3002 while (from <= to)
3004 lcv = 0;
3005 lvp = 0;
3006 for (cv = display->d_cvlist; cv; cv = cv->c_next)
3008 if (y == cv->c_ye + 1 && from >= cv->c_xs && from <= cv->c_xe)
3010 p = Layer2Window(cv->c_layer);
3011 #ifdef SCRIPT
3012 /*FIXME: is it okey to bypass all the following code?*/
3013 if (trigger_sevent(&globalevents.processcaption, cv))
3014 continue;
3015 #endif
3016 buf = MakeWinMsgEv(captionstring, p, '%', cv->c_xe - cv->c_xs + (cv->c_xe + 1 < D_width || D_CLP), &cv->c_captev, 0);
3017 if (cv->c_captev.timeout.tv_sec)
3018 evenq(&cv->c_captev);
3019 xx = to > cv->c_xe ? cv->c_xe : to;
3020 l = strlen(buf);
3021 GotoPos(from, y);
3022 SetRendition(&mchar_so);
3023 if (l > xx - cv->c_xs + 1)
3024 l = xx - cv->c_xs + 1;
3025 PutWinMsg(buf, from - cv->c_xs, l);
3026 from = cv->c_xs + l;
3027 for (; from <= xx; from++)
3028 PUTCHARLP(' ');
3029 break;
3031 if (from == cv->c_xe + 1 && y >= cv->c_ys && y <= cv->c_ye + 1)
3033 GotoPos(from, y);
3034 SetRendition(&mchar_so);
3035 PUTCHARLP(' ');
3036 from++;
3037 break;
3039 if (y < cv->c_ys || y > cv->c_ye || to < cv->c_xs || from > cv->c_xe)
3040 continue;
3041 debug2("- canvas hit: %d %d", cv->c_xs, cv->c_ys);
3042 debug2(" %d %d\n", cv->c_xe, cv->c_ye);
3043 for (vp = cv->c_vplist; vp; vp = vp->v_next)
3045 debug2(" - vp: %d %d", vp->v_xs, vp->v_ys);
3046 debug2(" %d %d\n", vp->v_xe, vp->v_ye);
3047 /* find leftmost overlapping vp */
3048 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))
3050 lcv = cv;
3051 lvp = vp;
3055 if (cv)
3056 continue; /* we advanced from */
3057 if (lvp == 0)
3058 break;
3059 if (from < lvp->v_xs)
3061 if (!isblank)
3062 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xs - 1);
3063 from = lvp->v_xs;
3066 /* call LayRedisplayLine on canvas lcv viewport lvp */
3067 yy = y - lvp->v_yoff;
3068 xx = to < lvp->v_xe ? to : lvp->v_xe;
3070 if (lcv->c_layer && yy == lcv->c_layer->l_height)
3072 GotoPos(from, y);
3073 SetRendition(&mchar_blank);
3074 while (from <= lvp->v_xe && from - lvp->v_xoff < lcv->c_layer->l_width)
3076 PUTCHARLP('-');
3077 from++;
3079 if (from >= lvp->v_xe + 1)
3080 continue;
3082 if (lcv->c_layer == 0 || yy >= lcv->c_layer->l_height || from - lvp->v_xoff >= lcv->c_layer->l_width)
3084 if (!isblank)
3085 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xe);
3086 from = lvp->v_xe + 1;
3087 continue;
3090 if (xx - lvp->v_xoff >= lcv->c_layer->l_width)
3091 xx = lcv->c_layer->l_width + lvp->v_xoff - 1;
3092 oldflayer = flayer;
3093 flayer = lcv->c_layer;
3094 cvlist = flayer->l_cvlist;
3095 cvlnext = lcv->c_lnext;
3096 flayer->l_cvlist = lcv;
3097 lcv->c_lnext = 0;
3098 LayRedisplayLine(yy, from - lvp->v_xoff, xx - lvp->v_xoff, isblank);
3099 flayer->l_cvlist = cvlist;
3100 lcv->c_lnext = cvlnext;
3101 flayer = oldflayer;
3103 from = xx + 1;
3105 if (!isblank && from <= to)
3106 DisplayLine(&mline_null, &mline_blank, y, from, to);
3109 /*********************************************************************/
3111 /* clear lp_missing by writing the char on the screen. The
3112 * position must be safe.
3114 static void
3115 WriteLP(x2, y2)
3116 int x2, y2;
3118 struct mchar oldrend;
3120 ASSERT(display);
3121 ASSERT(D_lp_missing);
3122 oldrend = D_rend;
3123 debug2("WriteLP(%d,%d)\n", x2, y2);
3124 #ifdef DW_CHARS
3125 if (D_lpchar.mbcs)
3127 if (x2 > 0)
3128 x2--;
3129 else
3130 D_lpchar = mchar_blank;
3132 #endif
3133 /* Can't use PutChar */
3134 GotoPos(x2, y2);
3135 SetRendition(&D_lpchar);
3136 PUTCHAR(D_lpchar.image);
3137 #ifdef DW_CHARS
3138 if (D_lpchar.mbcs)
3139 PUTCHAR(D_lpchar.mbcs);
3140 #endif
3141 D_lp_missing = 0;
3142 SetRendition(&oldrend);
3145 void
3146 ClearLine(oml, y, from, to, bce)
3147 struct mline *oml;
3148 int from, to, y, bce;
3150 int x;
3151 #ifdef COLOR
3152 struct mchar bcechar;
3153 #endif
3155 debug3("ClearLine %d,%d-%d\n", y, from, to);
3156 if (D_UT) /* Safe to erase ? */
3157 SetRendition(&mchar_null);
3158 #ifdef COLOR
3159 if (D_BE)
3160 SetBackColor(bce);
3161 #endif
3162 if (from == 0 && D_CB && (to != D_width - 1 || (D_x == to && D_y == y)) && (!bce || D_BE))
3164 GotoPos(to, y);
3165 AddCStr(D_CB);
3166 return;
3168 if (to == D_width - 1 && D_CE && (!bce || D_BE))
3170 GotoPos(from, y);
3171 AddCStr(D_CE);
3172 return;
3174 if (oml == 0)
3175 oml = &mline_null;
3176 #ifdef COLOR
3177 if (!bce)
3179 DisplayLine(oml, &mline_blank, y, from, to);
3180 return;
3182 bcechar = mchar_blank;
3183 rend_setbg(&bcechar, bce);
3184 for (x = from; x <= to; x++)
3185 copy_mchar2mline(&bcechar, &mline_old, x);
3186 DisplayLine(oml, &mline_old, y, from, to);
3187 #else
3188 DisplayLine(oml, &mline_blank, y, from, to);
3189 #endif
3192 void
3193 DisplayLine(oml, ml, y, from, to)
3194 struct mline *oml, *ml;
3195 int from, to, y;{
3197 register int x;
3198 int last2flag = 0, delete_lp = 0;
3200 ASSERT(display);
3201 ASSERT(y >= 0 && y < D_height);
3202 ASSERT(from >= 0 && from < D_width);
3203 ASSERT(to >= 0 && to < D_width);
3204 if (!D_CLP && y == D_bot && to == D_width - 1)
3206 if (D_lp_missing || !cmp_mline(oml, ml, to))
3208 #ifdef DW_CHARS
3209 if ((D_IC || D_IM) && from < to && !dw_left(ml, to, D_encoding))
3210 #else
3211 if ((D_IC || D_IM) && from < to)
3212 #endif
3214 last2flag = 1;
3215 D_lp_missing = 0;
3216 to--;
3218 else
3220 delete_lp = !cmp_mchar_mline(&mchar_blank, oml, to) && (D_CE || D_DC || D_CDC);
3221 D_lp_missing = !cmp_mchar_mline(&mchar_blank, ml, to);
3222 copy_mline2mchar(&D_lpchar, ml, to);
3225 to--;
3227 #ifdef DW_CHARS
3228 if (D_mbcs)
3230 /* finish dw-char (can happen after a wrap) */
3231 debug("DisplayLine finishing kanji\n");
3232 SetRenditionMline(ml, from);
3233 PUTCHAR(ml->image[from]);
3234 from++;
3236 #endif
3237 for (x = from; x <= to; x++)
3239 #if 0 /* no longer needed */
3240 if (x || D_x != D_width || D_y != y - 1)
3241 #endif
3243 if (x < to || x != D_width - 1 || ml->image[x + 1])
3244 if (cmp_mline(oml, ml, x))
3245 continue;
3246 GotoPos(x, y);
3248 #ifdef DW_CHARS
3249 if (dw_right(ml, x, D_encoding))
3251 x--;
3252 debug1("DisplayLine on right side of dw char- x now %d\n", x);
3253 GotoPos(x, y);
3255 if (x == to && dw_left(ml, x, D_encoding))
3256 break; /* don't start new kanji */
3257 #endif
3258 SetRenditionMline(ml, x);
3259 PUTCHAR(ml->image[x]);
3260 #ifdef DW_CHARS
3261 if (dw_left(ml, x, D_encoding))
3262 PUTCHAR(ml->image[++x]);
3263 #endif
3265 #if 0 /* not needed any longer */
3266 /* compare != 0 because ' ' can happen when clipping occures */
3267 if (to == D_width - 1 && y < D_height - 1 && D_x == D_width && ml->image[to + 1])
3268 GotoPos(0, y + 1);
3269 #endif
3270 if (last2flag)
3272 GotoPos(x, y);
3273 SetRenditionMline(ml, x + 1);
3274 PUTCHAR(ml->image[x + 1]);
3275 GotoPos(x, y);
3276 SetRenditionMline(ml, x);
3277 INSERTCHAR(ml->image[x]);
3279 else if (delete_lp)
3281 if (D_UT)
3282 SetRendition(&mchar_null);
3283 if (D_DC)
3284 AddCStr(D_DC);
3285 else if (D_CDC)
3286 AddCStr2(D_CDC, 1);
3287 else if (D_CE)
3288 AddCStr(D_CE);
3292 void
3293 PutChar(c, x, y)
3294 struct mchar *c;
3295 int x, y;
3297 GotoPos(x, y);
3298 SetRendition(c);
3299 PUTCHARLP(c->image);
3300 #ifdef DW_CHARS
3301 if (c->mbcs)
3303 # ifdef UTF8
3304 if (D_encoding == UTF8)
3305 D_rend.font = 0;
3306 # endif
3307 PUTCHARLP(c->mbcs);
3309 #endif
3312 void
3313 InsChar(c, x, xe, y, oml)
3314 struct mchar *c;
3315 int x, xe, y;
3316 struct mline *oml;
3318 GotoPos(x, y);
3319 if (y == D_bot && !D_CLP)
3321 if (x == D_width - 1)
3323 D_lp_missing = 1;
3324 D_lpchar = *c;
3325 return;
3327 if (xe == D_width - 1)
3328 D_lp_missing = 0;
3330 if (x == xe)
3332 SetRendition(c);
3333 PUTCHARLP(c->image);
3334 return;
3336 if (!(D_IC || D_CIC || D_IM) || xe != D_width - 1)
3338 RefreshLine(y, x, xe, 0);
3339 GotoPos(x + 1, y);
3340 /* UpdateLine(oml, y, x, xe); */
3341 return;
3343 InsertMode(1);
3344 if (!D_insert)
3346 #ifdef DW_CHARS
3347 if (c->mbcs && D_IC)
3348 AddCStr(D_IC);
3349 if (D_IC)
3350 AddCStr(D_IC);
3351 else
3352 AddCStr2(D_CIC, c->mbcs ? 2 : 1);
3353 #else
3354 if (D_IC)
3355 AddCStr(D_IC);
3356 else
3357 AddCStr2(D_CIC, 1);
3358 #endif
3360 SetRendition(c);
3361 RAW_PUTCHAR(c->image);
3362 #ifdef DW_CHARS
3363 if (c->mbcs)
3365 # ifdef UTF8
3366 if (D_encoding == UTF8)
3367 D_rend.font = 0;
3368 # endif
3369 if (D_x == D_width - 1)
3370 PUTCHARLP(c->mbcs);
3371 else
3372 RAW_PUTCHAR(c->mbcs);
3374 #endif
3377 void
3378 WrapChar(c, x, y, xs, ys, xe, ye, ins)
3379 struct mchar *c;
3380 int x, y;
3381 int xs, ys, xe, ye;
3382 int ins;
3384 int bce;
3386 #ifdef COLOR
3387 bce = rend_getbg(c);
3388 #else
3389 bce = 0;
3390 #endif
3391 debug("WrapChar:");
3392 debug2(" x %d y %d", x, y);
3393 debug2(" Dx %d Dy %d", D_x, D_y);
3394 debug2(" xs %d ys %d", xs, ys);
3395 debug3(" xe %d ye %d ins %d\n", xe, ye, ins);
3396 if (xs != 0 || x != D_width || !D_AM)
3398 if (y == ye)
3399 ScrollV(xs, ys, xe, ye, 1, bce);
3400 else if (y < D_height - 1)
3401 y++;
3402 if (ins)
3403 InsChar(c, xs, xe, y, 0);
3404 else
3405 PutChar(c, xs, y);
3406 return;
3408 if (y == ye) /* we have to scroll */
3410 debug("- scrolling\n");
3411 ChangeScrollRegion(ys, ye);
3412 if (D_bot != y || D_x != D_width || (!bce && !D_BE))
3414 debug("- have to call ScrollV\n");
3415 ScrollV(xs, ys, xe, ye, 1, bce);
3416 y--;
3419 else if (y == D_bot) /* remove unusable region? */
3420 ChangeScrollRegion(0, D_height - 1);
3421 if (D_x != D_width || D_y != y)
3423 if (D_CLP && y >= 0) /* don't even try if !LP */
3424 RefreshLine(y, D_width - 1, D_width - 1, 0);
3425 debug2("- refresh last char -> x,y now %d,%d\n", D_x, D_y);
3426 if (D_x != D_width || D_y != y) /* sorry, no bonus */
3428 if (y == ye)
3429 ScrollV(xs, ys, xe, ye, 1, bce);
3430 GotoPos(xs, y == ye || y == D_height - 1 ? y : y + 1);
3433 debug("- writeing new char");
3434 if (y != ye && y < D_height - 1)
3435 y++;
3436 if (ins != D_insert)
3437 InsertMode(ins);
3438 if (ins && !D_insert)
3440 InsChar(c, 0, xe, y, 0);
3441 debug2(" -> done with insert (%d,%d)\n", D_x, D_y);
3442 return;
3444 D_y = y;
3445 D_x = 0;
3446 SetRendition(c);
3447 RAW_PUTCHAR(c->image);
3448 #ifdef DW_CHARS
3449 if (c->mbcs)
3451 # ifdef UTF8
3452 if (D_encoding == UTF8)
3453 D_rend.font = 0;
3454 # endif
3455 RAW_PUTCHAR(c->mbcs);
3457 #endif
3458 debug2(" -> done (%d,%d)\n", D_x, D_y);
3462 ResizeDisplay(wi, he)
3463 int wi, he;
3465 ASSERT(display);
3466 debug2("ResizeDisplay: to (%d,%d).\n", wi, he);
3467 if (D_width == wi && D_height == he)
3469 debug("ResizeDisplay: No change\n");
3470 return 0;
3472 if (D_width != wi && (D_height == he || !D_CWS) && D_CZ0 && (wi == Z0width || wi == Z1width))
3474 debug("ResizeDisplay: using Z0/Z1\n");
3475 AddCStr(wi == Z0width ? D_CZ0 : D_CZ1);
3476 ChangeScreenSize(wi, D_height, 0);
3477 return (he == D_height) ? 0 : -1;
3479 if (D_CWS)
3481 debug("ResizeDisplay: using WS\n");
3482 AddCStr(tgoto(D_CWS, wi, he));
3483 ChangeScreenSize(wi, he, 0);
3484 return 0;
3486 return -1;
3489 void
3490 ChangeScrollRegion(newtop, newbot)
3491 int newtop, newbot;
3493 if (display == 0)
3494 return;
3495 if (newtop == newbot)
3496 return; /* xterm etc can't do it */
3497 if (newtop == -1)
3498 newtop = 0;
3499 if (newbot == -1)
3500 newbot = D_height - 1;
3501 if (D_CS == 0)
3503 D_top = 0;
3504 D_bot = D_height - 1;
3505 return;
3507 if (D_top == newtop && D_bot == newbot)
3508 return;
3509 debug2("ChangeScrollRegion: (%d - %d)\n", newtop, newbot);
3510 AddCStr(tgoto(D_CS, newbot, newtop));
3511 D_top = newtop;
3512 D_bot = newbot;
3513 D_y = D_x = -1; /* Just in case... */
3516 #ifdef RXVT_OSC
3517 void
3518 SetXtermOSC(i, s)
3519 int i;
3520 char *s;
3522 static char oscs[] = "1;\000\00020;\00039;\00049;\000";
3524 ASSERT(display);
3525 if (!D_CXT)
3526 return;
3527 if (!s)
3528 s = "";
3529 if (!D_xtermosc[i] && !*s)
3530 return;
3531 if (i == 0 && !*s)
3532 s = "screen"; /* always set icon name */
3533 if (i == 1 && !*s)
3534 s = ""; /* no background */
3535 if (i == 2 && !*s)
3536 s = "black"; /* black text */
3537 if (i == 3 && !*s)
3538 s = "white"; /* on white background */
3539 D_xtermosc[i] = 1;
3540 AddStr("\033]");
3541 AddStr(oscs + i * 4);
3542 AddStr(s);
3543 AddChar(7);
3546 void
3547 ClearAllXtermOSC()
3549 int i;
3550 for (i = 3; i >= 0; i--)
3551 SetXtermOSC(i, 0);
3553 #endif
3556 * Output buffering routines
3559 void
3560 AddStr(str)
3561 char *str;
3563 register char c;
3565 ASSERT(display);
3567 #ifdef UTF8
3568 if (D_encoding == UTF8)
3570 while ((c = *str++))
3571 AddUtf8((unsigned char)c);
3572 return;
3574 #endif
3575 while ((c = *str++))
3576 AddChar(c);
3579 void
3580 AddStrn(str, n)
3581 char *str;
3582 int n;
3584 register char c;
3586 ASSERT(display);
3587 #ifdef UTF8
3588 if (D_encoding == UTF8)
3590 while ((c = *str++) && n-- > 0)
3591 AddUtf8((unsigned char)c);
3593 else
3594 #endif
3595 while ((c = *str++) && n-- > 0)
3596 AddChar(c);
3597 while (n-- > 0)
3598 AddChar(' ');
3601 void
3602 Flush()
3604 register int l;
3605 register char *p;
3607 ASSERT(display);
3608 l = D_obufp - D_obuf;
3609 debug1("Flush(): %d\n", l);
3610 if (l == 0)
3611 return;
3612 ASSERT(l + D_obuffree == D_obuflen);
3613 if (D_userfd < 0)
3615 D_obuffree += l;
3616 D_obufp = D_obuf;
3617 return;
3619 p = D_obuf;
3620 if (fcntl(D_userfd, F_SETFL, 0))
3621 debug1("Warning: BLOCK fcntl failed: %d\n", errno);
3622 while (l)
3624 register int wr;
3625 wr = write(D_userfd, p, l);
3626 if (wr <= 0)
3628 if (errno == EINTR)
3629 continue;
3630 debug1("Writing to display: %d\n", errno);
3631 wr = l;
3633 if (!display)
3634 return;
3635 D_obuffree += wr;
3636 p += wr;
3637 l -= wr;
3639 D_obuffree += l;
3640 D_obufp = D_obuf;
3641 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
3642 debug1("Warning: NBLOCK fcntl failed: %d\n", errno);
3643 if (D_blocked == 1)
3644 D_blocked = 0;
3645 D_blocked_fuzz = 0;
3648 void
3649 freetty()
3651 if (D_userfd >= 0)
3652 close(D_userfd);
3653 debug1("did freetty %d\n", D_userfd);
3654 D_userfd = -1;
3655 D_obufp = 0;
3656 D_obuffree = 0;
3657 if (D_obuf)
3658 free(D_obuf);
3659 D_obuf = 0;
3660 D_obuflen = 0;
3661 D_obuflenmax = -D_obufmax;
3662 D_blocked = 0;
3663 D_blocked_fuzz = 0;
3667 * Asynchronous output routines by
3668 * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
3671 void
3672 Resize_obuf()
3674 register int ind;
3676 ASSERT(display);
3677 if (D_status_obuffree >= 0)
3679 ASSERT(D_obuffree == -1);
3680 if (!D_status_bell)
3682 struct timeval now;
3683 int ti;
3684 gettimeofday(&now, NULL);
3685 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
3686 if (ti < MsgMinWait)
3687 DisplaySleep1000(MsgMinWait - ti, 0);
3689 RemoveStatus();
3690 if (--D_obuffree > 0) /* redo AddChar decrement */
3691 return;
3693 if (D_obuflen && D_obuf)
3695 ind = D_obufp - D_obuf;
3696 D_obuflen += GRAIN;
3697 D_obuffree += GRAIN;
3698 D_obuf = realloc(D_obuf, D_obuflen);
3700 else
3702 ind = 0;
3703 D_obuflen = GRAIN;
3704 D_obuffree = GRAIN;
3705 D_obuf = malloc(D_obuflen);
3707 if (!D_obuf)
3708 Panic(0, "Out of memory");
3709 D_obufp = D_obuf + ind;
3710 D_obuflenmax = D_obuflen - D_obufmax;
3711 debug1("ResizeObuf: resized to %d\n", D_obuflen);
3714 void
3715 DisplaySleep1000(n, eat)
3716 int n;
3717 int eat;
3719 char buf;
3720 fd_set r;
3721 struct timeval t;
3723 if (n <= 0)
3724 return;
3725 if (!display)
3727 debug("DisplaySleep has no display sigh\n");
3728 sleep1000(n);
3729 return;
3731 t.tv_usec = (n % 1000) * 1000;
3732 t.tv_sec = n / 1000;
3733 FD_ZERO(&r);
3734 FD_SET(D_userfd, &r);
3735 if (select(FD_SETSIZE, &r, (fd_set *)0, (fd_set *)0, &t) > 0)
3737 debug("display activity stopped sleep\n");
3738 if (eat)
3739 read(D_userfd, &buf, 1);
3741 debug2("DisplaySleep(%d) ending, eat was %d\n", n, eat);
3744 #ifdef AUTO_NUKE
3745 void
3746 NukePending()
3747 {/* Nuke pending output in current display, clear screen */
3748 register int len;
3749 int oldtop = D_top, oldbot = D_bot;
3750 struct mchar oldrend;
3751 int oldkeypad = D_keypad, oldcursorkeys = D_cursorkeys;
3752 int oldcurvis = D_curvis;
3753 int oldmouse = D_mouse;
3755 oldrend = D_rend;
3756 len = D_obufp - D_obuf;
3757 debug1("NukePending: nuking %d chars\n", len);
3759 /* Throw away any output that we can... */
3760 # ifdef POSIX
3761 tcflush(D_userfd, TCOFLUSH);
3762 # else
3763 # ifdef TCFLSH
3764 (void) ioctl(D_userfd, TCFLSH, (char *) 1);
3765 # endif
3766 # endif
3768 D_obufp = D_obuf;
3769 D_obuffree += len;
3770 D_top = D_bot = -1;
3771 AddCStr(D_IS);
3772 AddCStr(D_TI);
3773 /* Turn off all attributes. (Tim MacKenzie) */
3774 if (D_ME)
3775 AddCStr(D_ME);
3776 else
3778 #ifdef COLOR
3779 if (D_hascolor)
3780 AddStr("\033[m"); /* why is D_ME not set? */
3781 #endif
3782 AddCStr(D_SE);
3783 AddCStr(D_UE);
3785 /* Check for toggle */
3786 if (D_IM && strcmp(D_IM, D_EI))
3787 AddCStr(D_EI);
3788 D_insert = 0;
3789 /* Check for toggle */
3790 #ifdef MAPKEYS
3791 if (D_KS && strcmp(D_KS, D_KE))
3792 AddCStr(D_KS);
3793 if (D_CCS && strcmp(D_CCS, D_CCE))
3794 AddCStr(D_CCS);
3795 #else
3796 if (D_KS && strcmp(D_KS, D_KE))
3797 AddCStr(D_KE);
3798 D_keypad = 0;
3799 if (D_CCS && strcmp(D_CCS, D_CCE))
3800 AddCStr(D_CCE);
3801 D_cursorkeys = 0;
3802 #endif
3803 AddCStr(D_CE0);
3804 D_rend = mchar_null;
3805 D_atyp = 0;
3806 AddCStr(D_DS);
3807 D_hstatus = 0;
3808 AddCStr(D_VE);
3809 D_curvis = 0;
3810 ChangeScrollRegion(oldtop, oldbot);
3811 SetRendition(&oldrend);
3812 KeypadMode(oldkeypad);
3813 CursorkeysMode(oldcursorkeys);
3814 CursorVisibility(oldcurvis);
3815 MouseMode(oldmouse);
3816 if (D_CWS)
3818 debug("ResizeDisplay: using WS\n");
3819 AddCStr(tgoto(D_CWS, D_width, D_height));
3821 else if (D_CZ0 && (D_width == Z0width || D_width == Z1width))
3823 debug("ResizeDisplay: using Z0/Z1\n");
3824 AddCStr(D_width == Z0width ? D_CZ0 : D_CZ1);
3827 #endif /* AUTO_NUKE */
3829 #ifdef linux
3830 /* linux' select can't handle flow control, so wait 100ms if
3831 * we get EAGAIN
3833 static void
3834 disp_writeev_eagain(ev, data)
3835 struct event *ev;
3836 char *data;
3838 display = (struct display *)data;
3839 evdeq(&D_writeev);
3840 D_writeev.type = EV_WRITE;
3841 D_writeev.handler = disp_writeev_fn;
3842 evenq(&D_writeev);
3844 #endif
3846 static void
3847 disp_writeev_fn(ev, data)
3848 struct event *ev;
3849 char *data;
3851 int len, size = OUTPUT_BLOCK_SIZE;
3853 display = (struct display *)data;
3854 len = D_obufp - D_obuf;
3855 if (len < size)
3856 size = len;
3857 ASSERT(len >= 0);
3858 size = write(D_userfd, D_obuf, size);
3859 if (size >= 0)
3861 len -= size;
3862 if (len)
3864 bcopy(D_obuf + size, D_obuf, len);
3865 debug2("ASYNC: wrote %d - remaining %d\n", size, len);
3867 D_obufp -= size;
3868 D_obuffree += size;
3869 if (D_blocked_fuzz)
3871 D_blocked_fuzz -= size;
3872 if (D_blocked_fuzz < 0)
3873 D_blocked_fuzz = 0;
3875 if (D_blockedev.queued)
3877 if (D_obufp - D_obuf > D_obufmax / 2)
3879 debug2("%s: resetting timeout to %g secs\n", D_usertty, D_nonblock/1000.);
3880 SetTimeout(&D_blockedev, D_nonblock);
3882 else
3884 debug1("%s: deleting blocked timeout\n", D_usertty);
3885 evdeq(&D_blockedev);
3888 if (D_blocked == 1 && D_obuf == D_obufp)
3890 /* empty again, restart output */
3891 debug1("%s: buffer empty, unblocking\n", D_usertty);
3892 D_blocked = 0;
3893 Activate(D_fore ? D_fore->w_norefresh : 0);
3894 D_blocked_fuzz = D_obufp - D_obuf;
3897 else
3899 #ifdef linux
3900 /* linux flow control is badly broken */
3901 if (errno == EAGAIN)
3903 evdeq(&D_writeev);
3904 D_writeev.type = EV_TIMEOUT;
3905 D_writeev.handler = disp_writeev_eagain;
3906 SetTimeout(&D_writeev, 100);
3907 evenq(&D_writeev);
3909 #endif
3910 if (errno != EINTR && errno != EAGAIN)
3911 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3912 if (errno != EWOULDBLOCK)
3913 #endif
3914 Msg(errno, "Error writing output to display");
3918 static void
3919 disp_readev_fn(ev, data)
3920 struct event *ev;
3921 char *data;
3923 int size;
3924 char buf[IOSIZE];
3925 struct canvas *cv;
3927 display = (struct display *)data;
3929 /* Hmmmm... a bit ugly... */
3930 if (D_forecv)
3931 for (cv = D_forecv->c_layer->l_cvlist; cv; cv = cv->c_lnext)
3933 display = cv->c_display;
3934 if (D_status == STATUS_ON_WIN)
3935 RemoveStatus();
3938 display = (struct display *)data;
3939 if (D_fore == 0)
3940 size = IOSIZE;
3941 else
3943 #ifdef PSEUDOS
3944 if (W_UWP(D_fore))
3945 size = sizeof(D_fore->w_pwin->p_inbuf) - D_fore->w_pwin->p_inlen;
3946 else
3947 #endif
3948 size = sizeof(D_fore->w_inbuf) - D_fore->w_inlen;
3951 if (size > IOSIZE)
3952 size = IOSIZE;
3953 if (size <= 0)
3954 size = 1; /* Always allow one char for command keys */
3956 size = read(D_userfd, buf, size);
3957 if (size < 0)
3959 if (errno == EINTR || errno == EAGAIN)
3960 return;
3961 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3962 if (errno == EWOULDBLOCK)
3963 return;
3964 #endif
3965 debug1("Read error: %d - hangup!\n", errno);
3966 Hangup();
3967 sleep(1);
3968 return;
3970 else if (size == 0)
3972 debug("Found EOF - hangup!\n");
3973 Hangup();
3974 sleep(1);
3975 return;
3977 if (D_blocked == 4)
3979 D_blocked = 0;
3980 #ifdef BLANKER_PRG
3981 KillBlanker();
3982 #endif
3983 Activate(D_fore ? D_fore->w_norefresh : 0);
3984 ResetIdle();
3985 return;
3987 #ifdef ZMODEM
3988 if (D_blocked > 1) /* 2, 3 */
3990 char *bufp;
3991 struct win *p;
3993 flayer = 0;
3994 for (p = windows; p ; p = p->w_next)
3995 if (p->w_zdisplay == display)
3997 flayer = &p->w_layer;
3998 bufp = buf;
3999 while (size > 0)
4000 LayProcess(&bufp, &size);
4001 return;
4003 debug("zmodem window gone, deblocking display");
4004 zmodem_abort(0, display);
4006 #endif
4007 if (idletimo > 0)
4008 ResetIdle();
4009 if (D_fore)
4010 D_fore->w_lastdisp = display;
4011 if (D_mouse && D_forecv)
4013 unsigned char *bp = (unsigned char *)buf;
4014 int x, y, i = size;
4016 /* XXX this assumes that the string is read in as a whole... */
4017 for (i = size; i > 0; i--, bp++)
4019 if (i > 5 && bp[0] == 033 && bp[1] == '[' && bp[2] == 'M')
4021 bp++;
4022 i--;
4024 else if (i < 5 || bp[0] != 0233 || bp[1] != 'M')
4025 continue;
4026 x = bp[3] - 33;
4027 y = bp[4] - 33;
4028 if (x >= D_forecv->c_xs && x <= D_forecv->c_xe && y >= D_forecv->c_ys && y <= D_forecv->c_ye)
4030 x -= D_forecv->c_xoff;
4031 y -= D_forecv->c_yoff;
4032 if (x >= 0 && x < D_forecv->c_layer->l_width && y >= 0 && y < D_forecv->c_layer->l_height)
4034 bp[3] = x + 33;
4035 bp[4] = y + 33;
4036 i -= 4;
4037 bp += 4;
4038 continue;
4041 if (bp[0] == '[')
4043 bcopy((char *)bp + 1, (char *)bp, i);
4044 bp--;
4045 size--;
4047 if (i > 5)
4048 bcopy((char *)bp + 5, (char *)bp, i - 5);
4049 bp--;
4050 i -= 4;
4051 size -= 5;
4054 #ifdef ENCODINGS
4055 if (D_encoding != (D_forecv ? D_forecv->c_layer->l_encoding : 0))
4057 int i, j, c, enc;
4058 char buf2[IOSIZE * 2 + 10];
4059 enc = D_forecv ? D_forecv->c_layer->l_encoding : 0;
4060 for (i = j = 0; i < size; i++)
4062 c = ((unsigned char *)buf)[i];
4063 c = DecodeChar(c, D_encoding, &D_decodestate);
4064 if (c == -2)
4065 i--; /* try char again */
4066 if (c < 0)
4067 continue;
4068 if (pastefont)
4070 int font = 0;
4071 j += EncodeChar(buf2 + j, c, enc, &font);
4072 j += EncodeChar(buf2 + j, -1, enc, &font);
4074 else
4075 j += EncodeChar(buf2 + j, c, enc, 0);
4076 if (j > (int)sizeof(buf2) - 10) /* just in case... */
4077 break;
4079 (*D_processinput)(buf2, j);
4080 return;
4082 #endif
4083 (*D_processinput)(buf, size);
4086 static void
4087 disp_status_fn(ev, data)
4088 struct event *ev;
4089 char *data;
4091 display = (struct display *)data;
4092 debug1("disp_status_fn for display %x\n", (int)display);
4093 if (D_status)
4094 RemoveStatus();
4097 static void
4098 disp_hstatus_fn(ev, data)
4099 struct event *ev;
4100 char *data;
4102 display = (struct display *)data;
4103 if (D_status == STATUS_ON_HS)
4105 SetTimeout(ev, 1);
4106 evenq(ev);
4107 return;
4109 RefreshHStatus();
4112 static void
4113 disp_blocked_fn(ev, data)
4114 struct event *ev;
4115 char *data;
4117 struct win *p;
4119 display = (struct display *)data;
4120 debug1("blocked timeout %s\n", D_usertty);
4121 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
4123 debug("stopping output to display\n");
4124 D_blocked = 1;
4125 /* re-enable all windows */
4126 for (p = windows; p; p = p->w_next)
4127 if (p->w_readev.condneg == &D_obuflenmax)
4129 debug1("freeing window #%d\n", p->w_number);
4130 p->w_readev.condpos = p->w_readev.condneg = 0;
4135 static void
4136 cv_winid_fn(ev, data)
4137 struct event *ev;
4138 char *data;
4140 int ox, oy;
4141 struct canvas *cv = (struct canvas *)data;
4143 display = cv->c_display;
4144 if (D_status == STATUS_ON_WIN)
4146 SetTimeout(ev, 1);
4147 evenq(ev);
4148 return;
4150 ox = D_x;
4151 oy = D_y;
4152 if (cv->c_ye + 1 < D_height)
4153 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
4154 if (ox != -1 && oy != -1)
4155 GotoPos(ox, oy);
4158 #ifdef MAPKEYS
4159 static void
4160 disp_map_fn(ev, data)
4161 struct event *ev;
4162 char *data;
4164 char *p;
4165 int l, i;
4166 unsigned char *q;
4167 display = (struct display *)data;
4168 debug("Flushing map sequence\n");
4169 if (!(l = D_seql))
4170 return;
4171 p = (char *)D_seqp - l;
4172 D_seqp = D_kmaps + 3;
4173 D_seql = 0;
4174 if ((q = D_seqh) != 0)
4176 D_seqh = 0;
4177 i = q[0] << 8 | q[1];
4178 i &= ~KMAP_NOTIMEOUT;
4179 debug1("Mapping former hit #%d - ", i);
4180 debug2("%d(%s) - ", q[2], q + 3);
4181 if (StuffKey(i))
4182 ProcessInput2((char *)q + 3, q[2]);
4183 if (display == 0)
4184 return;
4185 l -= q[2];
4186 p += q[2];
4188 else
4189 D_dontmap = 1;
4190 ProcessInput(p, l);
4192 #endif
4194 static void
4195 disp_idle_fn(ev, data)
4196 struct event *ev;
4197 char *data;
4199 struct display *olddisplay;
4200 display = (struct display *)data;
4201 #ifdef SCRIPT
4202 if (trigger_sevent(&display->d_sev.onidle, display))
4203 return;
4204 #endif
4205 debug("idle timeout\n");
4206 if (idletimo <= 0 || idleaction.nr == RC_ILLEGAL)
4207 return;
4208 olddisplay = display;
4209 flayer = D_forecv->c_layer;
4210 fore = D_fore;
4211 DoAction(&idleaction, -1);
4212 if (idleaction.nr == RC_BLANKER)
4213 return;
4214 for (display = displays; display; display = display->d_next)
4215 if (olddisplay == display)
4216 break;
4217 if (display)
4218 ResetIdle();
4221 void
4222 ResetIdle()
4224 if (idletimo > 0)
4226 SetTimeout(&D_idleev, idletimo);
4227 if (!D_idleev.queued)
4228 evenq(&D_idleev);
4230 else
4231 evdeq(&D_idleev);
4235 #ifdef BLANKER_PRG
4237 static void
4238 disp_blanker_fn(ev, data)
4239 struct event *ev;
4240 char *data;
4242 char buf[IOSIZE], *b;
4243 int size;
4245 display = (struct display *)data;
4246 size = read(D_blankerev.fd, buf, IOSIZE);
4247 if (size <= 0)
4249 evdeq(&D_blankerev);
4250 close(D_blankerev.fd);
4251 D_blankerev.fd = -1;
4252 return;
4254 for (b = buf; size; size--)
4255 AddChar(*b++);
4258 void
4259 KillBlanker()
4261 int oldtop = D_top, oldbot = D_bot;
4262 struct mchar oldrend;
4264 if (D_blankerev.fd == -1)
4265 return;
4266 if (D_blocked == 4)
4267 D_blocked = 0;
4268 evdeq(&D_blankerev);
4269 close(D_blankerev.fd);
4270 D_blankerev.fd = -1;
4271 Kill(D_blankerpid, SIGHUP);
4272 D_top = D_bot = -1;
4273 oldrend = D_rend;
4274 if (D_ME)
4276 AddCStr(D_ME);
4277 AddCStr(D_ME);
4279 else
4281 #ifdef COLOR
4282 if (D_hascolor)
4283 AddStr("\033[m\033[m"); /* why is D_ME not set? */
4284 #endif
4285 AddCStr(D_SE);
4286 AddCStr(D_UE);
4288 AddCStr(D_VE);
4289 AddCStr(D_CE0);
4290 D_rend = mchar_null;
4291 D_atyp = 0;
4292 D_curvis = 0;
4293 D_x = D_y = -1;
4294 ChangeScrollRegion(oldtop, oldbot);
4295 SetRendition(&oldrend);
4296 ClearAll();
4299 void
4300 RunBlanker(cmdv)
4301 char **cmdv;
4303 char *m;
4304 int pid;
4305 int slave = -1;
4306 char termname[30];
4307 #ifndef TIOCSWINSZ
4308 char libuf[20], cobuf[20];
4309 #endif
4310 char **np;
4312 strcpy(termname, "TERM=");
4313 strncpy(termname + 5, D_termname, sizeof(termname) - 6);
4314 termname[sizeof(termname) - 1] = 0;
4315 KillBlanker();
4316 D_blankerpid = -1;
4317 if ((D_blankerev.fd = OpenPTY(&m)) == -1)
4319 Msg(0, "OpenPty failed");
4320 return;
4322 #ifdef O_NOCTTY
4323 if (pty_preopen)
4325 if ((slave = open(m, O_RDWR|O_NOCTTY)) == -1)
4327 Msg(errno, "%s", m);
4328 close(D_blankerev.fd);
4329 D_blankerev.fd = -1;
4330 return;
4333 #endif
4334 switch (pid = (int)fork())
4336 case -1:
4337 Msg(errno, "fork");
4338 close(D_blankerev.fd);
4339 D_blankerev.fd = -1;
4340 return;
4341 case 0:
4342 displays = 0;
4343 #ifdef DEBUG
4344 if (dfp && dfp != stderr)
4346 fclose(dfp);
4347 dfp = 0;
4349 #endif
4350 if (setgid(real_gid) || setuid(real_uid))
4351 Panic(errno, "setuid/setgid");
4352 brktty(D_userfd);
4353 freetty();
4354 close(0);
4355 close(1);
4356 close(2);
4357 closeallfiles(slave);
4358 if (open(m, O_RDWR))
4359 Panic(errno, "Cannot open %s", m);
4360 dup(0);
4361 dup(0);
4362 if (slave != -1)
4363 close(slave);
4364 InitPTY(0);
4365 fgtty(0);
4366 SetTTY(0, &D_OldMode);
4367 np = NewEnv + 3;
4368 *np++ = NewEnv[0];
4369 *np++ = termname;
4370 #ifdef TIOCSWINSZ
4371 glwz.ws_col = D_width;
4372 glwz.ws_row = D_height;
4373 (void)ioctl(0, TIOCSWINSZ, (char *)&glwz);
4374 #else
4375 sprintf(libuf, "LINES=%d", D_height);
4376 sprintf(cobuf, "COLUMNS=%d", D_width);
4377 *np++ = libuf;
4378 *np++ = cobuf;
4379 #endif
4380 #ifdef SIGPIPE
4381 signal(SIGPIPE, SIG_DFL);
4382 #endif
4383 display = 0;
4384 execvpe(*cmdv, cmdv, NewEnv + 3);
4385 Panic(errno, "%s", *cmdv);
4386 default:
4387 break;
4389 D_blankerpid = pid;
4390 evenq(&D_blankerev);
4391 D_blocked = 4;
4392 ClearAll();
4395 #endif
4397 struct layout *layouts;
4398 struct layout *laytab[MAXLAY];
4399 struct layout *layout_last, layout_last_marker;
4400 struct layout *layout_attach = &layout_last_marker;
4402 void
4403 FreeLayoutCv(cv)
4404 struct canvas *cv;
4406 struct canvas *cnext, *c = cv;
4407 for (; cv; cv = cnext)
4409 if (cv->c_slperp)
4411 FreeLayoutCv(cv->c_slperp);
4412 free(cv->c_slperp);
4413 cv->c_slperp = 0;
4415 cnext = cv->c_slnext;
4416 cv->c_slnext = 0;
4417 if (cv != c)
4418 free(cv);
4422 static void
4423 DupLayoutCv(cvf, cvt, save)
4424 struct canvas *cvf, *cvt;
4425 int save;
4427 while(cvf)
4429 cvt->c_slorient = cvf->c_slorient;
4430 cvt->c_slweight = cvf->c_slweight;
4431 if (cvf == D_forecv)
4432 D_forecv = cvt;
4433 if (!save)
4435 cvt->c_display = display;
4436 if (!cvf->c_slperp)
4438 cvt->c_captev.type = EV_TIMEOUT;
4439 cvt->c_captev.data = (char *)cvt;
4440 cvt->c_captev.handler = cv_winid_fn;
4441 cvt->c_blank.l_cvlist = 0;
4442 cvt->c_blank.l_layfn = &BlankLf;
4443 cvt->c_blank.l_bottom = &cvt->c_blank;
4445 cvt->c_layer = cvf->c_layer;
4447 else
4449 struct win *p = cvf->c_layer ? Layer2Window(cvf->c_layer) : 0;
4450 cvt->c_layer = p ? &p->w_layer : 0;
4452 if (cvf->c_slperp)
4454 cvt->c_slperp = (struct canvas *)calloc(1, sizeof(struct canvas));
4455 cvt->c_slperp->c_slback = cvt;
4456 CanvasInitBlank(cvt->c_slperp);
4457 DupLayoutCv(cvf->c_slperp, cvt->c_slperp, save);
4459 if (cvf->c_slnext)
4461 cvt->c_slnext = (struct canvas *)calloc(1, sizeof(struct canvas));
4462 cvt->c_slnext->c_slprev = cvt;
4463 cvt->c_slnext->c_slback = cvt->c_slback;
4464 CanvasInitBlank(cvt->c_slnext);
4466 cvf = cvf->c_slnext;
4467 cvt = cvt->c_slnext;
4471 void
4472 PutWindowCv(cv)
4473 struct canvas *cv;
4475 struct win *p;
4476 for (; cv; cv = cv->c_slnext)
4478 if (cv->c_slperp)
4480 PutWindowCv(cv->c_slperp);
4481 continue;
4483 p = cv->c_layer ? (struct win *)cv->c_layer->l_data : 0;
4484 cv->c_layer = 0;
4485 SetCanvasWindow(cv, p);
4489 struct layout *
4490 CreateLayout(title, startat)
4491 char *title;
4492 int startat;
4494 struct layout *lay;
4495 int i;
4497 if (startat >= MAXLAY || startat < 0)
4498 startat = 0;
4499 for (i = startat; ;)
4501 if (!laytab[i])
4502 break;
4503 if (++i == MAXLAY)
4504 i = 0;
4505 if (i == startat)
4507 Msg(0, "No more layouts\n");
4508 return 0;
4511 lay = (struct layout *)calloc(1, sizeof(*lay));
4512 lay->lay_title = SaveStr(title);
4513 lay->lay_autosave = 1;
4514 lay->lay_number = i;
4515 laytab[i] = lay;
4516 lay->lay_next = layouts;
4517 layouts = lay;
4518 return lay;
4521 void
4522 SaveLayout(name, cv)
4523 char *name;
4524 struct canvas *cv;
4526 struct layout *lay;
4527 struct canvas *fcv;
4528 for (lay = layouts; lay; lay = lay->lay_next)
4529 if (!strcmp(lay->lay_title, name))
4530 break;
4531 if (lay)
4532 FreeLayoutCv(&lay->lay_canvas);
4533 else
4534 lay = CreateLayout(name, 0);
4535 if (!lay)
4536 return;
4537 fcv = D_forecv;
4538 DupLayoutCv(cv, &lay->lay_canvas, 1);
4539 lay->lay_forecv = D_forecv;
4540 D_forecv = fcv;
4541 D_layout = lay;
4544 void
4545 AutosaveLayout(lay)
4546 struct layout *lay;
4548 struct canvas *fcv;
4549 if (!lay || !lay->lay_autosave)
4550 return;
4551 FreeLayoutCv(&lay->lay_canvas);
4552 fcv = D_forecv;
4553 DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
4554 lay->lay_forecv = D_forecv;
4555 D_forecv = fcv;
4558 struct layout *
4559 FindLayout(name)
4560 char *name;
4562 struct layout *lay;
4563 char *s;
4564 int i;
4565 for (i = 0, s = name; *s >= '0' && *s <= '9'; s++)
4566 i = i * 10 + (*s - '0');
4567 if (!*s && s != name && i >= 0 && i < MAXLAY)
4568 return laytab[i];
4569 for (lay = layouts; lay; lay = lay->lay_next)
4570 if (!strcmp(lay->lay_title, name))
4571 break;
4572 return lay;
4575 void
4576 LoadLayout(lay, cv)
4577 struct layout *lay;
4578 struct canvas *cv;
4580 AutosaveLayout(D_layout);
4581 if (!lay)
4583 while (D_canvas.c_slperp)
4584 FreeCanvas(D_canvas.c_slperp);
4585 MakeDefaultCanvas();
4586 SetCanvasWindow(D_forecv, 0);
4587 D_layout = 0;
4588 return;
4590 while (D_canvas.c_slperp)
4591 FreeCanvas(D_canvas.c_slperp);
4592 D_cvlist = 0;
4593 D_forecv = lay->lay_forecv;
4594 DupLayoutCv(&lay->lay_canvas, &D_canvas, 0);
4595 D_canvas.c_ye = D_height - 1 - ((D_canvas.c_slperp && D_canvas.c_slperp->c_slnext) || captionalways) - (D_has_hstatus == HSTATUS_LASTLINE);
4596 ResizeCanvas(&D_canvas);
4597 RecreateCanvasChain();
4598 RethinkDisplayViewports();
4599 PutWindowCv(&D_canvas);
4600 ResizeLayersToCanvases();
4601 D_layout = lay;
4604 void
4605 NewLayout(title, startat)
4606 char *title;
4607 int startat;
4609 struct layout *lay;
4610 struct canvas *fcv;
4612 lay = CreateLayout(title, startat);
4613 if (!lay)
4614 return;
4615 LoadLayout(0, &D_canvas);
4616 fcv = D_forecv;
4617 DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
4618 lay->lay_forecv = D_forecv;
4619 D_forecv = fcv;
4620 D_layout = lay;
4621 lay->lay_autosave = 1;
4624 static char *
4625 AddLayoutsInfo(buf, len, where)
4626 char *buf;
4627 int len;
4628 int where;
4630 char *s, *ss, *t;
4631 struct layout *p, **pp;
4632 int l;
4634 s = ss = buf;
4635 for (pp = laytab; pp < laytab + MAXLAY; pp++)
4637 if (pp - laytab == where && ss == buf)
4638 ss = s;
4639 if ((p = *pp) == 0)
4640 continue;
4641 t = p->lay_title;
4642 l = strlen(t);
4643 if (l > 20)
4644 l = 20;
4645 if (s - buf + l > len - 24)
4646 break;
4647 if (s > buf)
4649 *s++ = ' ';
4650 *s++ = ' ';
4652 sprintf(s, "%d", p->lay_number);
4653 if (p->lay_number == where)
4654 ss = s;
4655 s += strlen(s);
4656 if (display && p == D_layout)
4657 *s++ = '*';
4658 *s++ = ' ';
4659 strncpy(s, t, l);
4660 s += l;
4662 *s = 0;
4663 return ss;
4666 void
4667 ShowLayouts(where)
4668 int where;
4670 char buf[1024];
4671 char *s, *ss;
4673 if (!display)
4674 return;
4675 if (!layouts)
4677 Msg(0, "No layouts defined\n");
4678 return;
4680 if (where == -1 && D_layout)
4681 where = D_layout->lay_number;
4682 ss = AddLayoutsInfo(buf, sizeof(buf), where);
4683 s = buf + strlen(buf);
4684 if (ss - buf > D_width / 2)
4686 ss -= D_width / 2;
4687 if (s - ss < D_width)
4689 ss = s - D_width;
4690 if (ss < buf)
4691 ss = buf;
4694 else
4695 ss = buf;
4696 Msg(0, "%s", ss);
4699 void
4700 RemoveLayout(lay)
4701 struct layout *lay;
4703 struct layout **layp = &layouts;
4705 for (; *layp; layp = &(*layp)->lay_next)
4707 if (*layp == lay)
4709 *layp = lay->lay_next;
4710 break;
4713 laytab[lay->lay_number] = (struct layout *)0;
4715 if (display && D_layout == lay)
4716 D_layout = (struct layout *)0;
4718 FreeLayoutCv(&lay->lay_canvas);
4720 if (lay->lay_title)
4721 free(lay->lay_title);
4722 #ifdef SCRIPT
4723 broker_inv_obj(lay);
4724 #endif
4725 free(lay);
4727 if (layouts)
4728 LoadLayout((display && D_layout) ? D_layout : *layp ? *layp : layouts,
4729 display ? &D_canvas : (struct canvas *)0);
4730 Activate(0);