Add support for mouse tracking.
[screen-lua.git] / src / display.c
blobd25328d86949401df8147f606716f382ee648b62
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 *));
70 static void RemoveStatusMinWait __P((void));
73 extern struct layer *flayer;
74 extern struct win *windows, *fore;
75 extern struct LayFuncs WinLf;
77 extern int use_hardstatus;
78 extern int MsgWait, MsgMinWait;
79 extern int Z0width, Z1width;
80 extern unsigned char *blank, *null;
81 extern struct mline mline_blank, mline_null, mline_old;
82 extern struct mchar mchar_null, mchar_blank, mchar_so;
83 extern struct NewWindow nwin_default;
84 extern struct action idleaction;
86 /* XXX shouldn't be here */
87 extern char *hstatusstring;
88 extern char *captionstring;
90 extern int pastefont;
91 extern int idletimo;
93 #ifdef BLANKER_PRG
94 extern int pty_preopen;
95 #if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
96 extern struct winsize glwz;
97 #endif
98 extern char **NewEnv;
99 extern int real_uid, real_gid;
100 #endif
103 * tputs needs this to calculate the padding
105 #ifndef NEED_OSPEED
106 extern
107 #endif /* NEED_OSPEED */
108 short ospeed;
111 struct display *display, *displays;
112 #ifdef COLOR
113 int attr2color[8][4];
114 int nattr2color;
115 #endif
117 #ifndef MULTI
118 struct display TheDisplay;
119 #endif
122 * The default values
124 int defobuflimit = OBUF_MAX;
125 int defnonblock = -1;
126 int defmousetrack = 0;
127 #ifdef AUTO_NUKE
128 int defautonuke = 0;
129 #endif
130 int captionalways;
131 int hardstatusemu = HSTATUS_IGNORE;
133 int focusminwidth, focusminheight;
136 * Default layer management
139 void
140 DefProcess(bufp, lenp)
141 char **bufp;
142 int *lenp;
144 *bufp += *lenp;
145 *lenp = 0;
148 void
149 DefRedisplayLine(y, xs, xe, isblank)
150 int y, xs, xe, isblank;
152 if (isblank == 0 && y >= 0)
153 DefClearLine(y, xs, xe, 0);
156 void
157 DefClearLine(y, xs, xe, bce)
158 int y, xs, xe, bce;
160 LClearLine(flayer, y, xs, xe, bce, (struct mline *)0);
163 /*ARGSUSED*/
165 DefRewrite(y, xs, xe, rend, doit)
166 int y, xs, xe, doit;
167 struct mchar *rend;
169 return EXPENSIVE;
172 /*ARGSUSED*/
174 DefResize(wi, he)
175 int wi, he;
177 return -1;
180 void
181 DefRestore()
183 LAY_DISPLAYS(flayer, InsertMode(0));
184 /* ChangeScrollRegion(0, D_height - 1); */
185 LKeypadMode(flayer, 0);
186 LCursorkeysMode(flayer, 0);
187 LCursorVisibility(flayer, 0);
188 LMouseMode(flayer, 0);
189 LSetRendition(flayer, &mchar_null);
190 LSetFlow(flayer, nwin_default.flowflag & FLOW_NOW);
194 * Blank layer management
197 struct LayFuncs BlankLf =
199 DefProcess,
201 DefRedisplayLine,
202 DefClearLine,
203 DefRewrite,
204 BlankResize,
205 DefRestore
208 /*ARGSUSED*/
209 static int
210 BlankResize(wi, he)
211 int wi, he;
213 flayer->l_width = wi;
214 flayer->l_height = he;
215 return 0;
220 * Generate new display, start with a blank layer.
221 * The termcap arrays are not initialised here.
222 * The new display is placed in the displays list.
225 struct display *
226 MakeDisplay(uname, utty, term, fd, pid, Mode)
227 char *uname, *utty, *term;
228 int fd, pid;
229 struct mode *Mode;
231 struct acluser **u;
232 struct baud_values *b;
234 if (!*(u = FindUserPtr(uname)) && UserAdd(uname, (char *)0, u))
235 return 0; /* could not find or add user */
237 #ifdef MULTI
238 if ((display = (struct display *)calloc(1, sizeof(*display))) == 0)
239 return 0;
240 #else
241 if (displays)
242 return 0;
243 bzero((char *)&TheDisplay, sizeof(TheDisplay));
244 display = &TheDisplay;
245 #endif
246 display->d_next = displays;
247 displays = display;
248 D_flow = 1;
249 D_nonblock = defnonblock;
250 D_userfd = fd;
251 D_readev.fd = D_writeev.fd = fd;
252 D_readev.type = EV_READ;
253 D_writeev.type = EV_WRITE;
254 D_readev.data = D_writeev.data = (char *)display;
255 D_readev.handler = disp_readev_fn;
256 D_writeev.handler = disp_writeev_fn;
257 evenq(&D_readev);
258 D_writeev.condpos = &D_obuflen;
259 D_writeev.condneg = &D_obuffree;
260 evenq(&D_writeev);
261 D_statusev.type = EV_TIMEOUT;
262 D_statusev.data = (char *)display;
263 D_statusev.handler = disp_status_fn;
264 D_hstatusev.type = EV_TIMEOUT;
265 D_hstatusev.data = (char *)display;
266 D_hstatusev.handler = disp_hstatus_fn;
267 D_blockedev.type = EV_TIMEOUT;
268 D_blockedev.data = (char *)display;
269 D_blockedev.handler = disp_blocked_fn;
270 D_blockedev.condpos = &D_obuffree;
271 D_blockedev.condneg = &D_obuflenmax;
272 D_hstatusev.handler = disp_hstatus_fn;
273 #ifdef MAPKEYS
274 D_mapev.type = EV_TIMEOUT;
275 D_mapev.data = (char *)display;
276 D_mapev.handler = disp_map_fn;
277 #endif
278 D_idleev.type = EV_TIMEOUT;
279 D_idleev.data = (char *)display;
280 D_idleev.handler = disp_idle_fn;
281 #ifdef BLANKER_PRG
282 D_blankerev.type = EV_READ;
283 D_blankerev.data = (char *)display;
284 D_blankerev.handler = disp_blanker_fn;
285 D_blankerev.fd = -1;
286 #endif
287 D_OldMode = *Mode;
288 D_status_obuffree = -1;
289 Resize_obuf(); /* Allocate memory for buffer */
290 D_obufmax = defobuflimit;
291 D_obuflenmax = D_obuflen - D_obufmax;
292 #ifdef AUTO_NUKE
293 D_auto_nuke = defautonuke;
294 #endif
295 D_obufp = D_obuf;
296 D_printfd = -1;
297 D_userpid = pid;
299 #ifdef POSIX
300 if ((b = lookup_baud((int)cfgetospeed(&D_OldMode.tio))))
301 D_dospeed = b->idx;
302 #else
303 # ifdef TERMIO
304 if ((b = lookup_baud(D_OldMode.tio.c_cflag & CBAUD)))
305 D_dospeed = b->idx;
306 # else
307 D_dospeed = (short)D_OldMode.m_ttyb.sg_ospeed;
308 # endif
309 #endif
310 debug1("New displays ospeed = %d\n", D_dospeed);
312 strncpy(D_usertty, utty, sizeof(D_usertty) - 1);
313 D_usertty[sizeof(D_usertty) - 1] = 0;
314 strncpy(D_termname, term, sizeof(D_termname) - 1);
315 D_termname[sizeof(D_termname) - 1] = 0;
316 D_user = *u;
317 D_processinput = ProcessInput;
318 D_mousetrack = defmousetrack;
319 return display;
323 void
324 FreeDisplay()
326 struct win *p;
327 #ifdef MULTI
328 struct display *d, **dp;
329 #endif
331 #ifdef FONT
332 FreeTransTable();
333 #endif
334 #ifdef BLANKER_PRG
335 KillBlanker();
336 #endif
337 if (D_userfd >= 0)
339 Flush(3);
340 if (!display)
341 return;
342 SetTTY(D_userfd, &D_OldMode);
343 fcntl(D_userfd, F_SETFL, 0);
345 freetty();
346 if (D_tentry)
347 free(D_tentry);
348 D_tentry = 0;
349 if (D_processinputdata)
350 free(D_processinputdata);
351 D_processinputdata = 0;
352 D_tcinited = 0;
353 evdeq(&D_hstatusev);
354 evdeq(&D_statusev);
355 evdeq(&D_readev);
356 evdeq(&D_writeev);
357 evdeq(&D_blockedev);
358 #ifdef MAPKEYS
359 evdeq(&D_mapev);
360 if (D_kmaps)
362 free(D_kmaps);
363 D_kmaps = 0;
364 D_aseqs = 0;
365 D_nseqs = 0;
366 D_seqp = 0;
367 D_seql = 0;
368 D_seqh = 0;
370 #endif
371 evdeq(&D_idleev);
372 #ifdef BLANKER_PRG
373 evdeq(&D_blankerev);
374 #endif
375 #ifdef HAVE_BRAILLE
376 if (bd.bd_dpy == display)
378 bd.bd_start_braille = 0;
379 StartBraille();
381 #endif
383 #ifdef MULTI
384 for (dp = &displays; (d = *dp) ; dp = &d->d_next)
385 if (d == display)
386 break;
387 ASSERT(d);
388 if (D_status_lastmsg)
389 free(D_status_lastmsg);
390 if (D_obuf)
391 free(D_obuf);
392 *dp = display->d_next;
393 #else /* MULTI */
394 ASSERT(display == displays);
395 ASSERT(display == &TheDisplay);
396 displays = 0;
397 #endif /* MULTI */
399 while (D_canvas.c_slperp)
400 FreeCanvas(D_canvas.c_slperp);
401 D_cvlist = 0;
403 for (p = windows; p; p = p->w_next)
405 if (p->w_pdisplay == display)
406 p->w_pdisplay = 0;
407 if (p->w_lastdisp == display)
408 p->w_lastdisp = 0;
409 if (p->w_readev.condneg == &D_status || p->w_readev.condneg == &D_obuflenmax)
410 p->w_readev.condpos = p->w_readev.condneg = 0;
412 #ifdef ZMODEM
413 for (p = windows; p; p = p->w_next)
414 if (p->w_zdisplay == display)
415 zmodem_abort(p, 0);
416 #endif
417 if (D_mousetrack)
419 D_mousetrack = 0;
420 MouseMode(0);
422 #ifdef MULTI
423 free((char *)display);
424 #endif
425 display = 0;
428 static void
429 CanvasInitBlank(cv)
430 struct canvas *cv;
432 cv->c_blank.l_cvlist = cv;
433 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
434 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
435 cv->c_blank.l_x = cv->c_blank.l_y = 0;
436 cv->c_blank.l_layfn = &BlankLf;
437 cv->c_blank.l_data = 0;
438 cv->c_blank.l_next = 0;
439 cv->c_blank.l_bottom = &cv->c_blank;
440 cv->c_blank.l_blocking = 0;
441 cv->c_layer = &cv->c_blank;
445 MakeDefaultCanvas()
447 struct canvas *cv;
449 ASSERT(display);
450 if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
451 return -1;
452 cv->c_xs = 0;
453 cv->c_xe = D_width - 1;
454 cv->c_ys = 0;
455 cv->c_ye = D_height - 1 - (D_has_hstatus == HSTATUS_LASTLINE) - captionalways;
456 debug2("MakeDefaultCanvas 0,0 %d,%d\n", cv->c_xe, cv->c_ye);
457 cv->c_xoff = 0;
458 cv->c_yoff = 0;
459 cv->c_next = 0;
460 cv->c_display = display;
461 cv->c_vplist = 0;
462 cv->c_slnext = 0;
463 cv->c_slprev = 0;
464 cv->c_slperp = 0;
465 cv->c_slweight = 1;
466 cv->c_slback = &D_canvas;
467 D_canvas.c_slperp = cv;
468 D_canvas.c_xs = cv->c_xs;
469 D_canvas.c_xe = cv->c_xe;
470 D_canvas.c_ys = cv->c_ys;
471 D_canvas.c_ye = cv->c_ye;
472 cv->c_slorient = SLICE_UNKN;
473 cv->c_captev.type = EV_TIMEOUT;
474 cv->c_captev.data = (char *)cv;
475 cv->c_captev.handler = cv_winid_fn;
477 CanvasInitBlank(cv);
478 cv->c_lnext = 0;
480 D_cvlist = cv;
481 RethinkDisplayViewports();
482 D_forecv = cv; /* default input focus */
483 return 0;
486 static struct canvas **
487 CreateCanvasChainRec(cv, cvp)
488 struct canvas *cv;
489 struct canvas **cvp;
491 for (; cv; cv = cv->c_slnext)
493 if (cv->c_slperp)
494 cvp = CreateCanvasChainRec(cv->c_slperp, cvp);
495 else
497 *cvp = cv;
498 cvp = &cv->c_next;
501 return cvp;
504 void
505 RecreateCanvasChain()
507 struct canvas **cvp;
508 cvp = CreateCanvasChainRec(D_canvas.c_slperp, &D_cvlist);
509 *cvp = 0;
512 static void
513 FreeCanvas(cv)
514 struct canvas *cv;
516 struct viewport *vp, *nvp;
517 struct canvas **cvp;
518 struct win *p;
520 if (cv->c_slprev)
521 cv->c_slprev->c_slnext = cv->c_slnext;
522 if (cv->c_slnext)
523 cv->c_slnext->c_slprev = cv->c_slprev;
524 if (cv->c_slback && cv->c_slback->c_slperp == cv)
525 cv->c_slback->c_slperp = cv->c_slnext ? cv->c_slnext : cv->c_slprev;
526 if (cv->c_slperp)
528 while (cv->c_slperp)
529 FreeCanvas(cv->c_slperp);
530 free(cv);
531 return;
534 if (display)
536 if (D_forecv == cv)
537 D_forecv = 0;
538 /* remove from canvas chain as SetCanvasWindow might call
539 * some layer function */
540 for (cvp = &D_cvlist; *cvp ; cvp = &(*cvp)->c_next)
541 if (*cvp == cv)
543 *cvp = cv->c_next;
544 break;
547 p = cv->c_layer ? Layer2Window(cv->c_layer) : 0;
548 SetCanvasWindow(cv, 0);
549 if (p)
550 WindowChanged(p, 'u');
551 if (flayer == cv->c_layer)
552 flayer = 0;
553 for (vp = cv->c_vplist; vp; vp = nvp)
555 vp->v_canvas = 0;
556 nvp = vp->v_next;
557 vp->v_next = 0;
558 free(vp);
560 evdeq(&cv->c_captev);
561 free(cv);
565 CountCanvas(cv)
566 struct canvas *cv;
568 int num = 0;
569 for (; cv; cv = cv->c_slnext)
571 if (cv->c_slperp)
573 struct canvas *cvp;
574 int nump = 1, n;
575 for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
576 if (cvp->c_slperp)
578 n = CountCanvas(cvp->c_slperp);
579 if (n > nump)
580 nump = n;
582 num += nump;
584 else
585 num++;
587 return num;
591 CountCanvasPerp(cv)
592 struct canvas *cv;
594 struct canvas *cvp;
595 int num = 1, n;
596 for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
597 if (cvp->c_slperp)
599 n = CountCanvas(cvp->c_slperp);
600 if (n > num)
601 num = n;
603 return num;
606 void
607 EqualizeCanvas(cv, gflag)
608 struct canvas *cv;
609 int gflag;
611 struct canvas *cv2;
612 for (; cv; cv = cv->c_slnext)
614 if (cv->c_slperp && gflag)
616 cv->c_slweight = CountCanvasPerp(cv);
617 for (cv2 = cv->c_slperp; cv2; cv2 = cv2->c_slnext)
618 if (cv2->c_slperp)
619 EqualizeCanvas(cv2->c_slperp, gflag);
621 else
622 cv->c_slweight = 1;
626 void
627 ResizeCanvas(cv)
628 struct canvas *cv;
630 struct canvas *cv2, *cvn, *fcv;
631 int nh, i, maxi, hh, m, w, wsum;
632 int need, got;
633 int xs, ys, xe, ye;
634 int focusmin = 0;
636 xs = cv->c_xs;
637 ys = cv->c_ys;
638 xe = cv->c_xe;
639 ye = cv->c_ye;
640 cv = cv->c_slperp;
641 debug2("ResizeCanvas: %d,%d", xs, ys);
642 debug2(" %d,%d\n", xe, ye);
643 if (cv == 0)
644 return;
645 if (cv->c_slorient == SLICE_UNKN)
647 ASSERT(!cv->c_slnext && !cv->c_slperp);
648 cv->c_xs = xs;
649 cv->c_xe = xe;
650 cv->c_ys = ys;
651 cv->c_ye = ye;
652 cv->c_xoff = cv->c_xs;
653 cv->c_yoff = cv->c_ys;
654 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
655 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
656 return;
659 fcv = 0;
660 if (focusminwidth || focusminheight)
662 debug("searching for focus canvas\n");
663 cv2 = D_forecv;
664 while (cv2->c_slback)
666 if (cv2->c_slback == cv->c_slback)
668 fcv = cv2;
669 focusmin = cv->c_slorient == SLICE_VERT ? focusminheight : focusminwidth;
670 if (focusmin > 0)
671 focusmin--;
672 else if (focusmin < 0)
673 focusmin = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
674 debug1("found, focusmin=%d\n", focusmin);
676 cv2 = cv2->c_slback;
679 if (focusmin)
681 m = CountCanvas(cv) * 2;
682 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
683 nh -= m;
684 if (nh < 0)
685 nh = 0;
686 if (focusmin > nh)
687 focusmin = nh;
688 debug1("corrected to %d\n", focusmin);
691 /* pass 1: calculate weight sum */
692 for (cv2 = cv, wsum = 0; cv2; cv2 = cv2->c_slnext)
694 debug1(" weight %d\n", cv2->c_slweight);
695 wsum += cv2->c_slweight;
697 debug1("wsum = %d\n", wsum);
698 if (wsum == 0)
699 wsum = 1;
700 w = wsum;
702 /* pass 2: calculate need/excess space */
703 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
704 for (cv2 = cv, need = got = 0; cv2; cv2 = cv2->c_slnext)
706 m = cv2->c_slperp ? CountCanvasPerp(cv2) * 2 - 1 : 1;
707 if (cv2 == fcv)
708 m += focusmin;
709 hh = cv2->c_slweight ? nh * cv2->c_slweight / w : 0;
710 w -= cv2->c_slweight;
711 nh -= hh;
712 debug2(" should %d min %d\n", hh, m);
713 if (hh <= m + 1)
714 need += m + 1 - hh;
715 else
716 got += hh - m - 1;
718 debug2("need: %d, got %d\n", need, got);
719 if (need > got)
720 need = got;
722 /* pass 3: distribute space */
723 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
724 i = cv->c_slorient == SLICE_VERT ? ys : xs;
725 maxi = cv->c_slorient == SLICE_VERT ? ye : xe;
726 w = wsum;
727 for (; cv; cv = cvn)
729 cvn = cv->c_slnext;
730 if (i > maxi)
732 if (cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slprev->c_slperp && !cv->c_slprev->c_slprev)
734 cv->c_slprev->c_slorient = SLICE_UNKN;
735 if (!captionalways)
737 cv->c_slback->c_ye++;
738 cv->c_slprev->c_ye++;
741 SetCanvasWindow(cv, 0);
742 FreeCanvas(cv);
743 continue;
745 m = cv->c_slperp ? CountCanvasPerp(cv) * 2 - 1 : 1;
746 if (cv == fcv)
747 m += focusmin;
748 hh = cv->c_slweight ? nh * cv->c_slweight / w : 0;
749 w -= cv->c_slweight;
750 nh -= hh;
751 debug2(" should %d min %d\n", hh, m);
752 if (hh <= m + 1)
754 hh = m + 1;
755 debug1(" -> %d\n", hh);
757 else
759 int hx = need * (hh - m - 1) / got;
760 debug3(" -> %d - %d = %d\n", hh, hx, hh - hx);
761 got -= (hh - m - 1);
762 hh -= hx;
763 need -= hx;
764 debug2(" now need=%d got=%d\n", need, got);
766 ASSERT(hh >= m + 1);
767 /* hh is window size plus pation line */
768 if (i + hh > maxi + 2)
770 hh = maxi + 2 - i;
771 debug1(" not enough space, reducing to %d\n", hh);
773 if (i + hh == maxi + 1)
775 hh++;
776 debug(" incrementing as no other canvas will fit\n");
778 if (cv->c_slorient == SLICE_VERT)
780 cv->c_xs = xs;
781 cv->c_xe = xe;
782 cv->c_ys = i;
783 cv->c_ye = i + hh - 2;
784 cv->c_xoff = xs;
785 cv->c_yoff = i;
787 else
789 cv->c_xs = i;
790 cv->c_xe = i + hh - 2;
791 cv->c_ys = ys;
792 cv->c_ye = ye;
793 cv->c_xoff = i;
794 cv->c_yoff = ys;
796 cv->c_xoff = cv->c_xs;
797 cv->c_yoff = cv->c_ys;
798 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
799 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
800 if (cv->c_slperp)
802 ResizeCanvas(cv);
803 if (!cv->c_slperp->c_slnext)
805 debug("deleting perp node\n");
806 FreePerp(cv->c_slperp);
807 FreePerp(cv);
810 i += hh;
814 static struct canvas *
815 AddPerp(cv)
816 struct canvas *cv;
818 struct canvas *pcv;
819 debug("Creating new perp node\n");
821 if ((pcv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
822 return 0;
823 pcv->c_next = 0;
824 pcv->c_display = cv->c_display;
825 pcv->c_slnext = cv->c_slnext;
826 pcv->c_slprev = cv->c_slprev;
827 pcv->c_slperp = cv;
828 pcv->c_slback = cv->c_slback;
829 if (cv->c_slback && cv->c_slback->c_slperp == cv)
830 cv->c_slback->c_slperp = pcv;
831 pcv->c_slorient = cv->c_slorient;
832 pcv->c_xoff = 0;
833 pcv->c_yoff = 0;
834 pcv->c_xs = cv->c_xs;
835 pcv->c_xe = cv->c_xe;
836 pcv->c_ys = cv->c_ys;
837 pcv->c_ye = cv->c_ye;
838 if (pcv->c_slnext)
839 pcv->c_slnext->c_slprev = pcv;
840 if (pcv->c_slprev)
841 pcv->c_slprev->c_slnext = pcv;
842 pcv->c_slweight = cv->c_slweight;
843 CanvasInitBlank(pcv);
844 cv->c_slweight = 1;
845 cv->c_slnext = 0;
846 cv->c_slprev = 0;
847 cv->c_slperp = 0;
848 cv->c_slback = pcv;
849 cv->c_slorient = SLICE_UNKN;
850 return pcv;
853 static void
854 FreePerp(pcv)
855 struct canvas *pcv;
857 struct canvas *cv;
859 if (!pcv->c_slperp)
860 return;
861 cv = pcv->c_slperp;
862 cv->c_slprev = pcv->c_slprev;
863 if (cv->c_slprev)
864 cv->c_slprev->c_slnext = cv;
865 cv->c_slback = pcv->c_slback;
866 if (cv->c_slback && cv->c_slback->c_slperp == pcv)
867 cv->c_slback->c_slperp = cv;
868 cv->c_slorient = pcv->c_slorient;
869 cv->c_slweight = pcv->c_slweight;
870 while (cv->c_slnext)
872 cv = cv->c_slnext;
873 cv->c_slorient = pcv->c_slorient;
874 cv->c_slback = pcv->c_slback;
875 cv->c_slweight = pcv->c_slweight;
877 cv->c_slnext = pcv->c_slnext;
878 if (cv->c_slnext)
879 cv->c_slnext->c_slprev = cv;
880 free(pcv);
884 AddCanvas(orient)
885 int orient;
887 struct canvas *cv;
888 int xs, xe, ys, ye;
889 int h, num;
891 cv = D_forecv;
892 debug2("AddCanvas orient %d, forecv is %d\n", orient, cv->c_slorient);
894 if (cv->c_slorient != SLICE_UNKN && cv->c_slorient != orient)
895 if (!AddPerp(cv))
896 return -1;
898 cv = D_forecv;
899 xs = cv->c_slback->c_xs;
900 xe = cv->c_slback->c_xe;
901 ys = cv->c_slback->c_ys;
902 ye = cv->c_slback->c_ye;
903 if (!captionalways && cv == D_canvas.c_slperp && !cv->c_slnext)
904 ye--; /* need space for caption */
905 debug2("Adding Canvas to slice %d,%d ", xs, ys);
906 debug2("%d,%d\n", xe, ye);
908 num = CountCanvas(cv->c_slback->c_slperp) + 1;
909 debug1("Num = %d\n", num);
910 if (orient == SLICE_VERT)
911 h = ye - ys + 1;
912 else
913 h = xe - xs + 1;
915 h -= 2 * num - 1;
916 if (h < 0)
917 return -1; /* can't fit in */
919 if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
920 return -1;
922 D_forecv->c_slback->c_ye = ye; /* in case we modified it above */
923 D_forecv->c_slorient = orient; /* in case it was UNKN */
924 cv->c_slnext = D_forecv->c_slnext;
925 cv->c_slprev = D_forecv;
926 D_forecv->c_slnext = cv;
927 if (cv->c_slnext)
928 cv->c_slnext->c_slprev = cv;
929 cv->c_slorient = orient;
930 cv->c_slback = D_forecv->c_slback;
932 cv->c_xs = xs;
933 cv->c_xe = xe;
934 cv->c_ys = ys;
935 cv->c_ye = ye;
936 cv->c_xoff = 0;
937 cv->c_yoff = 0;
938 cv->c_display = display;
939 cv->c_vplist = 0;
940 cv->c_captev.type = EV_TIMEOUT;
941 cv->c_captev.data = (char *)cv;
942 cv->c_captev.handler = cv_winid_fn;
944 CanvasInitBlank(cv);
945 cv->c_lnext = 0;
947 cv->c_next = 0;
949 cv = cv->c_slback;
950 EqualizeCanvas(cv->c_slperp, 0);
951 ResizeCanvas(cv);
952 RecreateCanvasChain();
953 RethinkDisplayViewports();
954 ResizeLayersToCanvases();
955 return 0;
958 void
959 RemCanvas()
961 int xs, xe, ys, ye;
962 struct canvas *cv;
964 debug("RemCanvas\n");
965 cv = D_forecv;
966 if (cv->c_slorient == SLICE_UNKN)
967 return;
968 while (cv->c_slprev)
969 cv = cv->c_slprev;
970 if (!cv->c_slnext)
971 return;
972 if (!cv->c_slnext->c_slnext && cv->c_slback->c_slback)
974 /* two canvases in slice, kill perp node */
975 cv = D_forecv;
976 debug("deleting perp node\n");
977 FreePerp(cv->c_slprev ? cv->c_slprev : cv->c_slnext);
978 FreePerp(cv->c_slback);
980 xs = cv->c_slback->c_xs;
981 xe = cv->c_slback->c_xe;
982 ys = cv->c_slback->c_ys;
983 ye = cv->c_slback->c_ye;
984 /* free canvas */
985 cv = D_forecv;
986 D_forecv = cv->c_slprev;
987 if (!D_forecv)
988 D_forecv = cv->c_slnext;
989 FreeCanvas(cv);
991 cv = D_forecv;
992 while (D_forecv->c_slperp)
993 D_forecv = D_forecv->c_slperp;
995 /* if only one canvas left, set orient back to unknown */
996 if (!cv->c_slnext && !cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slperp)
998 cv->c_slorient = SLICE_UNKN;
999 if (!captionalways)
1000 cv->c_slback->c_ye = ++ye; /* caption line no longer needed */
1002 cv = cv->c_slback;
1003 EqualizeCanvas(cv->c_slperp, 0);
1004 ResizeCanvas(cv);
1006 D_fore = Layer2Window(D_forecv->c_layer);
1007 flayer = D_forecv->c_layer;
1009 RecreateCanvasChain();
1010 RethinkDisplayViewports();
1011 ResizeLayersToCanvases();
1014 void
1015 OneCanvas()
1017 struct canvas *cv = D_forecv, *ocv = 0;
1019 if (cv->c_slprev)
1021 ocv = cv->c_slprev;
1022 cv->c_slprev->c_slnext = cv->c_slnext;
1024 if (cv->c_slnext)
1026 ocv = cv->c_slnext;
1027 cv->c_slnext->c_slprev = cv->c_slprev;
1029 if (!ocv)
1030 return;
1031 if (cv->c_slback && cv->c_slback->c_slperp == cv)
1032 cv->c_slback->c_slperp = ocv;
1033 cv->c_slorient = SLICE_UNKN;
1034 while (D_canvas.c_slperp)
1035 FreeCanvas(D_canvas.c_slperp);
1036 cv = D_forecv;
1037 D_canvas.c_slperp = cv;
1038 cv->c_slback = &D_canvas;
1039 cv->c_slnext = 0;
1040 cv->c_slprev = 0;
1041 ASSERT(!cv->c_slperp);
1042 if (!captionalways)
1043 D_canvas.c_ye++; /* caption line no longer needed */
1044 ResizeCanvas(&D_canvas);
1045 RecreateCanvasChain();
1046 RethinkDisplayViewports();
1047 ResizeLayersToCanvases();
1051 RethinkDisplayViewports()
1053 struct canvas *cv;
1054 struct viewport *vp, *vpn;
1056 /* free old viewports */
1057 for (cv = display->d_cvlist; cv; cv = cv->c_next)
1059 for (vp = cv->c_vplist; vp; vp = vpn)
1061 vp->v_canvas = 0;
1062 vpn = vp->v_next;
1063 bzero((char *)vp, sizeof(*vp));
1064 free(vp);
1066 cv->c_vplist = 0;
1068 display->d_vpxmin = -1;
1069 display->d_vpxmax = -1;
1071 for (cv = display->d_cvlist; cv; cv = cv->c_next)
1073 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1074 return -1;
1075 #ifdef HOLE
1076 vp->v_canvas = cv;
1077 vp->v_xs = cv->c_xs;
1078 vp->v_ys = (cv->c_ys + cv->c_ye) / 2;
1079 vp->v_xe = cv->c_xe;
1080 vp->v_ye = cv->c_ye;
1081 vp->v_xoff = cv->c_xoff;
1082 vp->v_yoff = cv->c_yoff;
1083 vp->v_next = cv->c_vplist;
1084 cv->c_vplist = vp;
1086 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1087 return -1;
1088 vp->v_canvas = cv;
1089 vp->v_xs = (cv->c_xs + cv->c_xe) / 2;
1090 vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
1091 vp->v_xe = cv->c_xe;
1092 vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
1093 vp->v_xoff = cv->c_xoff;
1094 vp->v_yoff = cv->c_yoff;
1095 vp->v_next = cv->c_vplist;
1096 cv->c_vplist = vp;
1098 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1099 return -1;
1100 vp->v_canvas = cv;
1101 vp->v_xs = cv->c_xs;
1102 vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
1103 vp->v_xe = (3 * cv->c_xs + cv->c_xe) / 4 - 1;
1104 vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
1105 vp->v_xoff = cv->c_xoff;
1106 vp->v_yoff = cv->c_yoff;
1107 vp->v_next = cv->c_vplist;
1108 cv->c_vplist = vp;
1110 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1111 return -1;
1112 vp->v_canvas = cv;
1113 vp->v_xs = cv->c_xs;
1114 vp->v_ys = cv->c_ys;
1115 vp->v_xe = cv->c_xe;
1116 vp->v_ye = (3 * cv->c_ys + cv->c_ye) / 4 - 1;
1117 vp->v_xoff = cv->c_xoff;
1118 vp->v_yoff = cv->c_yoff;
1119 vp->v_next = cv->c_vplist;
1120 cv->c_vplist = vp;
1121 #else
1122 vp->v_canvas = cv;
1123 vp->v_xs = cv->c_xs;
1124 vp->v_ys = cv->c_ys;
1125 vp->v_xe = cv->c_xe;
1126 vp->v_ye = cv->c_ye;
1127 vp->v_xoff = cv->c_xoff;
1128 vp->v_yoff = cv->c_yoff;
1129 vp->v_next = cv->c_vplist;
1130 cv->c_vplist = vp;
1131 #endif
1133 if (cv->c_xs < display->d_vpxmin || display->d_vpxmin == -1)
1134 display->d_vpxmin = cv->c_xs;
1135 if (cv->c_xe > display->d_vpxmax || display->d_vpxmax == -1)
1136 display->d_vpxmax = cv->c_xe;
1138 return 0;
1141 void
1142 RethinkViewportOffsets(cv)
1143 struct canvas *cv;
1145 struct viewport *vp;
1147 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1149 vp->v_xoff = cv->c_xoff;
1150 vp->v_yoff = cv->c_yoff;
1155 * if the adaptflag is on, we keep the size of this display, else
1156 * we may try to restore our old window sizes.
1158 void
1159 InitTerm(adapt)
1160 int adapt;
1162 ASSERT(display);
1163 ASSERT(D_tcinited);
1164 D_top = D_bot = -1;
1165 AddCStr(D_IS);
1166 AddCStr(D_TI);
1167 /* Check for toggle */
1168 if (D_IM && strcmp(D_IM, D_EI))
1169 AddCStr(D_EI);
1170 D_insert = 0;
1171 #ifdef MAPKEYS
1172 AddCStr(D_KS);
1173 AddCStr(D_CCS);
1174 #else
1175 /* Check for toggle */
1176 if (D_KS && strcmp(D_KS, D_KE))
1177 AddCStr(D_KE);
1178 if (D_CCS && strcmp(D_CCS, D_CCE))
1179 AddCStr(D_CCE);
1180 #endif
1181 D_keypad = 0;
1182 D_cursorkeys = 0;
1183 AddCStr(D_ME);
1184 AddCStr(D_EA);
1185 AddCStr(D_CE0);
1186 D_rend = mchar_null;
1187 D_atyp = 0;
1188 if (adapt == 0)
1189 ResizeDisplay(D_defwidth, D_defheight);
1190 ChangeScrollRegion(0, D_height - 1);
1191 D_x = D_y = 0;
1192 Flush(3);
1193 ClearAll();
1194 debug1("we %swant to adapt all our windows to the display\n",
1195 (adapt) ? "" : "don't ");
1196 /* In case the size was changed by a init sequence */
1197 CheckScreenSize((adapt) ? 2 : 0);
1200 void
1201 FinitTerm()
1203 ASSERT(display);
1204 #ifdef BLANKER_PRG
1205 KillBlanker();
1206 #endif
1207 if (D_tcinited)
1209 ResizeDisplay(D_defwidth, D_defheight);
1210 InsertMode(0);
1211 ChangeScrollRegion(0, D_height - 1);
1212 KeypadMode(0);
1213 CursorkeysMode(0);
1214 CursorVisibility(0);
1215 if (D_mousetrack)
1216 D_mousetrack = 0;
1217 MouseMode(0);
1218 SetRendition(&mchar_null);
1219 SetFlow(FLOW_NOW);
1220 #ifdef MAPKEYS
1221 AddCStr(D_KE);
1222 AddCStr(D_CCE);
1223 #endif
1224 if (D_hstatus)
1225 ShowHStatus((char *)0);
1226 #ifdef RXVT_OSC
1227 ClearAllXtermOSC();
1228 #endif
1229 D_x = D_y = -1;
1230 GotoPos(0, D_height - 1);
1231 AddChar('\r');
1232 AddChar('\n');
1233 AddCStr(D_TE);
1235 Flush(3);
1239 static void
1240 INSERTCHAR(c)
1241 int c;
1243 ASSERT(display);
1244 if (!D_insert && D_x < D_width - 1)
1246 if (D_IC || D_CIC)
1248 if (D_IC)
1249 AddCStr(D_IC);
1250 else
1251 AddCStr2(D_CIC, 1);
1252 RAW_PUTCHAR(c);
1253 return;
1255 InsertMode(1);
1256 if (!D_insert)
1258 RefreshLine(D_y, D_x, D_width-1, 0);
1259 return;
1262 RAW_PUTCHAR(c);
1265 void
1266 PUTCHAR(c)
1267 int c;
1269 ASSERT(display);
1270 if (D_insert && D_x < D_width - 1)
1271 InsertMode(0);
1272 RAW_PUTCHAR(c);
1275 void
1276 PUTCHARLP(c)
1277 int c;
1279 if (D_x < D_width - 1)
1281 if (D_insert)
1282 InsertMode(0);
1283 RAW_PUTCHAR(c);
1284 return;
1286 if (D_CLP || D_y != D_bot)
1288 int y = D_y;
1289 RAW_PUTCHAR(c);
1290 if (D_AM && !D_CLP)
1291 GotoPos(D_width - 1, y);
1292 return;
1294 debug("PUTCHARLP: lp_missing!\n");
1295 D_lp_missing = 1;
1296 D_rend.image = c;
1297 D_lpchar = D_rend;
1298 #ifdef DW_CHARS
1299 /* XXX -> PutChar ? */
1300 if (D_mbcs)
1302 D_lpchar.mbcs = c;
1303 D_lpchar.image = D_mbcs;
1304 D_mbcs = 0;
1305 D_x--;
1307 #endif
1311 * RAW_PUTCHAR() is for all text that will be displayed.
1312 * NOTE: charset Nr. 0 has a conversion table, but c1, c2, ... don't.
1315 STATIC void
1316 RAW_PUTCHAR(c)
1317 int c;
1319 ASSERT(display);
1321 #ifdef FONT
1322 # ifdef UTF8
1323 if (D_encoding == UTF8)
1325 c = (c & 255) | (unsigned char)D_rend.font << 8;
1326 # ifdef DW_CHARS
1327 if (D_mbcs)
1329 c = D_mbcs;
1330 if (D_x == D_width)
1331 D_x += D_AM ? 1 : -1;
1332 D_mbcs = 0;
1334 else if (utf8_isdouble(c))
1336 D_mbcs = c;
1337 D_x++;
1338 return;
1340 # endif
1341 if (c < 32)
1343 AddCStr2(D_CS0, '0');
1344 AddChar(c + 0x5f);
1345 AddCStr(D_CE0);
1346 goto addedutf8;
1348 AddUtf8(c);
1349 goto addedutf8;
1351 # endif
1352 # ifdef DW_CHARS
1353 if (is_dw_font(D_rend.font))
1355 int t = c;
1356 if (D_mbcs == 0)
1358 D_mbcs = c;
1359 D_x++;
1360 return;
1362 D_x--;
1363 if (D_x == D_width - 1)
1364 D_x += D_AM ? 1 : -1;
1365 c = D_mbcs;
1366 D_mbcs = t;
1368 # endif
1369 # if defined(ENCODINGS) && defined(DW_CHARS)
1370 if (D_encoding)
1371 c = PrepareEncodedChar(c);
1372 # endif
1373 # ifdef DW_CHARS
1374 kanjiloop:
1375 # endif
1376 if (D_xtable && D_xtable[(int)(unsigned char)D_rend.font] && D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c])
1377 AddStr(D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c]);
1378 else
1379 AddChar(D_rend.font != '0' ? c : D_c0_tab[(int)(unsigned char)c]);
1380 #else /* FONT */
1381 AddChar(c);
1382 #endif /* FONT */
1384 #ifdef UTF8
1385 addedutf8:
1386 #endif
1387 if (++D_x >= D_width)
1389 if (D_AM == 0)
1390 D_x = D_width - 1;
1391 else if (!D_CLP || D_x > D_width)
1393 D_x -= D_width;
1394 if (D_y < D_height-1 && D_y != D_bot)
1395 D_y++;
1398 #ifdef DW_CHARS
1399 if (D_mbcs)
1401 c = D_mbcs;
1402 D_mbcs = 0;
1403 goto kanjiloop;
1405 #endif
1408 static int
1409 DoAddChar(c)
1410 int c;
1412 /* this is for ESC-sequences only (AddChar is a macro) */
1413 AddChar(c);
1414 return c;
1417 void
1418 AddCStr(s)
1419 char *s;
1421 if (display && s && *s)
1423 ospeed = D_dospeed;
1424 tputs(s, 1, DoAddChar);
1428 void
1429 AddCStr2(s, c)
1430 char *s;
1431 int c;
1433 if (display && s && *s)
1435 ospeed = D_dospeed;
1436 tputs(tgoto(s, 0, c), 1, DoAddChar);
1441 /* Insert mode is a toggle on some terminals, so we need this hack:
1443 void
1444 InsertMode(on)
1445 int on;
1447 if (display && on != D_insert && D_IM)
1449 D_insert = on;
1450 if (on)
1451 AddCStr(D_IM);
1452 else
1453 AddCStr(D_EI);
1457 /* ...and maybe keypad application mode is a toggle, too:
1459 void
1460 KeypadMode(on)
1461 int on;
1463 #ifdef MAPKEYS
1464 if (display)
1465 D_keypad = on;
1466 #else
1467 if (display && D_keypad != on && D_KS)
1469 D_keypad = on;
1470 if (on)
1471 AddCStr(D_KS);
1472 else
1473 AddCStr(D_KE);
1475 #endif
1478 void
1479 CursorkeysMode(on)
1480 int on;
1482 #ifdef MAPKEYS
1483 if (display)
1484 D_cursorkeys = on;
1485 #else
1486 if (display && D_cursorkeys != on && D_CCS)
1488 D_cursorkeys = on;
1489 if (on)
1490 AddCStr(D_CCS);
1491 else
1492 AddCStr(D_CCE);
1494 #endif
1497 void
1498 ReverseVideo(on)
1499 int on;
1501 if (display && D_revvid != on && D_CVR)
1503 D_revvid = on;
1504 if (D_revvid)
1505 AddCStr(D_CVR);
1506 else
1507 AddCStr(D_CVN);
1511 void
1512 CursorVisibility(v)
1513 int v;
1515 if (display && D_curvis != v)
1517 if (D_curvis)
1518 AddCStr(D_VE); /* do this always, just to be safe */
1519 D_curvis = 0;
1520 if (v == -1 && D_VI)
1521 AddCStr(D_VI);
1522 else if (v == 1 && D_VS)
1523 AddCStr(D_VS);
1524 else
1525 return;
1526 D_curvis = v;
1530 void
1531 MouseMode(mode)
1532 int mode;
1534 if (!display)
1535 return;
1537 if (mode < D_mousetrack)
1538 mode = D_mousetrack;
1540 if (D_mouse != mode)
1542 char mousebuf[20];
1543 if (!D_CXT)
1544 return;
1545 if (D_mouse)
1547 sprintf(mousebuf, "\033[?%dl", D_mouse);
1548 AddStr(mousebuf);
1550 if (mode)
1552 sprintf(mousebuf, "\033[?%dh", mode);
1553 AddStr(mousebuf);
1555 D_mouse = mode;
1559 static int StrCost;
1561 /* ARGSUSED */
1562 static int
1563 CountChars(c)
1564 int c;
1566 StrCost++;
1567 return c;
1571 CalcCost(s)
1572 register char *s;
1574 ASSERT(display);
1575 if (s)
1577 StrCost = 0;
1578 ospeed = D_dospeed;
1579 tputs(s, 1, CountChars);
1580 return StrCost;
1582 else
1583 return EXPENSIVE;
1586 static int
1587 CallRewrite(y, xs, xe, doit)
1588 int y, xs, xe, doit;
1590 struct canvas *cv, *cvlist, *cvlnext;
1591 struct viewport *vp;
1592 struct layer *oldflayer;
1593 int cost;
1595 debug3("CallRewrite %d %d %d\n", y, xs, xe);
1596 ASSERT(display);
1597 ASSERT(xe >= xs);
1599 vp = 0;
1600 for (cv = D_cvlist; cv; cv = cv->c_next)
1602 if (y < cv->c_ys || y > cv->c_ye || xe < cv->c_xs || xs > cv->c_xe)
1603 continue;
1604 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1605 if (y >= vp->v_ys && y <= vp->v_ye && xe >= vp->v_xs && xs <= vp->v_xe)
1606 break;
1607 if (vp)
1608 break;
1610 if (doit)
1612 oldflayer = flayer;
1613 flayer = cv->c_layer;
1614 cvlist = flayer->l_cvlist;
1615 cvlnext = cv->c_lnext;
1616 flayer->l_cvlist = cv;
1617 cv->c_lnext = 0;
1618 LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 1);
1619 flayer->l_cvlist = cvlist;
1620 cv->c_lnext = cvlnext;
1621 flayer = oldflayer;
1622 return 0;
1624 if (cv == 0 || cv->c_layer == 0)
1625 return EXPENSIVE; /* not found or nothing on it */
1626 if (xs < vp->v_xs || xe > vp->v_xe)
1627 return EXPENSIVE; /* crosses viewport boundaries */
1628 if (y - vp->v_yoff < 0 || y - vp->v_yoff >= cv->c_layer->l_height)
1629 return EXPENSIVE; /* line not on layer */
1630 if (xs - vp->v_xoff < 0 || xe - vp->v_xoff >= cv->c_layer->l_width)
1631 return EXPENSIVE; /* line not on layer */
1632 #ifdef UTF8
1633 if (D_encoding == UTF8)
1634 D_rend.font = 0;
1635 #endif
1636 oldflayer = flayer;
1637 flayer = cv->c_layer;
1638 debug3("Calling Rewrite %d %d %d\n", y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff);
1639 cost = LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 0);
1640 flayer = oldflayer;
1641 if (D_insert)
1642 cost += D_EIcost + D_IMcost;
1643 return cost;
1647 void
1648 GotoPos(x2, y2)
1649 int x2, y2;
1651 register int dy, dx, x1, y1;
1652 register int costx, costy;
1653 register int m;
1654 register char *s;
1655 int CMcost;
1656 enum move_t xm = M_NONE, ym = M_NONE;
1658 if (!display)
1659 return;
1661 x1 = D_x;
1662 y1 = D_y;
1664 if (x1 == D_width)
1666 if (D_CLP && D_AM)
1667 x1 = -1; /* don't know how the terminal treats this */
1668 else
1669 x1--;
1671 if (x2 == D_width)
1672 x2--;
1673 dx = x2 - x1;
1674 dy = y2 - y1;
1675 if (dy == 0 && dx == 0)
1676 return;
1677 debug2("GotoPos (%d,%d)", x1, y1);
1678 debug2(" -> (%d,%d)\n", x2, y2);
1679 if (!D_MS) /* Safe to move ? */
1680 SetRendition(&mchar_null);
1681 if (y1 < 0 /* don't know the y position */
1682 || (y2 > D_bot && y1 <= D_bot) /* have to cross border */
1683 || (y2 < D_top && y1 >= D_top)) /* of scrollregion ? */
1685 DoCM:
1686 if (D_HO && !x2 && !y2)
1687 AddCStr(D_HO);
1688 else
1689 AddCStr(tgoto(D_CM, x2, y2));
1690 D_x = x2;
1691 D_y = y2;
1692 return;
1695 /* some scrollregion implementations don't allow movements
1696 * away from the region. sigh.
1698 if ((y1 > D_bot && y2 > y1) || (y1 < D_top && y2 < y1))
1699 goto DoCM;
1701 /* Calculate CMcost */
1702 if (D_HO && !x2 && !y2)
1703 s = D_HO;
1704 else
1705 s = tgoto(D_CM, x2, y2);
1706 CMcost = CalcCost(s);
1708 /* Calculate the cost to move the cursor to the right x position */
1709 costx = EXPENSIVE;
1710 if (x1 >= 0) /* relativ x positioning only if we know where we are */
1712 if (dx > 0)
1714 if (D_CRI && (dx > 1 || !D_ND))
1716 costx = CalcCost(tgoto(D_CRI, 0, dx));
1717 xm = M_CRI;
1719 if ((m = D_NDcost * dx) < costx)
1721 costx = m;
1722 xm = M_RI;
1724 /* Speedup: dx <= LayRewrite() */
1725 if (dx < costx && (m = CallRewrite(y1, x1, x2 - 1, 0)) < costx)
1727 costx = m;
1728 xm = M_RW;
1731 else if (dx < 0)
1733 if (D_CLE && (dx < -1 || !D_BC))
1735 costx = CalcCost(tgoto(D_CLE, 0, -dx));
1736 xm = M_CLE;
1738 if ((m = -dx * D_LEcost) < costx)
1740 costx = m;
1741 xm = M_LE;
1744 else
1745 costx = 0;
1747 /* Speedup: LayRewrite() >= x2 */
1748 if (x2 + D_CRcost < costx && (m = (x2 ? CallRewrite(y1, 0, x2 - 1, 0) : 0) + D_CRcost) < costx)
1750 costx = m;
1751 xm = M_CR;
1754 /* Check if it is already cheaper to do CM */
1755 if (costx >= CMcost)
1756 goto DoCM;
1758 /* Calculate the cost to move the cursor to the right y position */
1759 costy = EXPENSIVE;
1760 if (dy > 0)
1762 if (D_CDO && dy > 1) /* DO & NL are always != 0 */
1764 costy = CalcCost(tgoto(D_CDO, 0, dy));
1765 ym = M_CDO;
1767 if ((m = dy * ((x2 == 0) ? D_NLcost : D_DOcost)) < costy)
1769 costy = m;
1770 ym = M_DO;
1773 else if (dy < 0)
1775 if (D_CUP && (dy < -1 || !D_UP))
1777 costy = CalcCost(tgoto(D_CUP, 0, -dy));
1778 ym = M_CUP;
1780 if ((m = -dy * D_UPcost) < costy)
1782 costy = m;
1783 ym = M_UP;
1786 else
1787 costy = 0;
1789 /* Finally check if it is cheaper to do CM */
1790 if (costx + costy >= CMcost)
1791 goto DoCM;
1793 switch (xm)
1795 case M_LE:
1796 while (dx++ < 0)
1797 AddCStr(D_BC);
1798 break;
1799 case M_CLE:
1800 AddCStr2(D_CLE, -dx);
1801 break;
1802 case M_RI:
1803 while (dx-- > 0)
1804 AddCStr(D_ND);
1805 break;
1806 case M_CRI:
1807 AddCStr2(D_CRI, dx);
1808 break;
1809 case M_CR:
1810 AddCStr(D_CR);
1811 D_x = 0;
1812 x1 = 0;
1813 /* FALLTHROUGH */
1814 case M_RW:
1815 if (x1 < x2)
1816 (void) CallRewrite(y1, x1, x2 - 1, 1);
1817 break;
1818 default:
1819 break;
1822 switch (ym)
1824 case M_UP:
1825 while (dy++ < 0)
1826 AddCStr(D_UP);
1827 break;
1828 case M_CUP:
1829 AddCStr2(D_CUP, -dy);
1830 break;
1831 case M_DO:
1832 s = (x2 == 0) ? D_NL : D_DO;
1833 while (dy-- > 0)
1834 AddCStr(s);
1835 break;
1836 case M_CDO:
1837 AddCStr2(D_CDO, dy);
1838 break;
1839 default:
1840 break;
1842 D_x = x2;
1843 D_y = y2;
1846 void
1847 ClearAll()
1849 ASSERT(display);
1850 ClearArea(0, 0, 0, D_width - 1, D_width - 1, D_height - 1, 0, 0);
1853 void
1854 ClearArea(x1, y1, xs, xe, x2, y2, bce, uselayfn)
1855 int x1, y1, xs, xe, x2, y2, bce, uselayfn;
1857 int y, xxe;
1858 struct canvas *cv;
1859 struct viewport *vp;
1861 debug2("Clear %d,%d", x1, y1);
1862 debug2(" %d-%d", xs, xe);
1863 debug2(" %d,%d", x2, y2);
1864 debug2(" uselayfn=%d bce=%d\n", uselayfn, bce);
1865 ASSERT(display);
1866 if (x1 == D_width)
1867 x1--;
1868 if (x2 == D_width)
1869 x2--;
1870 if (xs == -1)
1871 xs = x1;
1872 if (xe == -1)
1873 xe = x2;
1874 if (D_UT) /* Safe to erase ? */
1875 SetRendition(&mchar_null);
1876 #ifdef COLOR
1877 if (D_BE)
1878 SetBackColor(bce);
1879 #endif
1880 if (D_lp_missing && y1 <= D_bot && xe >= D_width - 1)
1882 if (y2 > D_bot || (y2 == D_bot && x2 >= D_width - 1))
1883 D_lp_missing = 0;
1885 if (x2 == D_width - 1 && (xs == 0 || y1 == y2) && xe == D_width - 1 && y2 == D_height - 1 && (!bce || D_BE))
1887 #ifdef AUTO_NUKE
1888 if (x1 == 0 && y1 == 0 && D_auto_nuke)
1889 NukePending();
1890 #endif
1891 if (x1 == 0 && y1 == 0 && D_CL)
1893 AddCStr(D_CL);
1894 D_y = D_x = 0;
1895 return;
1898 * Workaround a hp700/22 terminal bug. Do not use CD where CE
1899 * is also appropriate.
1901 if (D_CD && (y1 < y2 || !D_CE))
1903 GotoPos(x1, y1);
1904 AddCStr(D_CD);
1905 return;
1908 if (x1 == 0 && xs == 0 && (xe == D_width - 1 || y1 == y2) && y1 == 0 && D_CCD && (!bce || D_BE))
1910 GotoPos(x1, y1);
1911 AddCStr(D_CCD);
1912 return;
1914 xxe = xe;
1915 for (y = y1; y <= y2; y++, x1 = xs)
1917 if (y == y2)
1918 xxe = x2;
1919 if (x1 == 0 && D_CB && (xxe != D_width - 1 || (D_x == xxe && D_y == y)) && (!bce || D_BE))
1921 GotoPos(xxe, y);
1922 AddCStr(D_CB);
1923 continue;
1925 if (xxe == D_width - 1 && D_CE && (!bce || D_BE))
1927 GotoPos(x1, y);
1928 AddCStr(D_CE);
1929 continue;
1931 if (uselayfn)
1933 vp = 0;
1934 for (cv = D_cvlist; cv; cv = cv->c_next)
1936 if (y < cv->c_ys || y > cv->c_ye || xxe < cv->c_xs || x1 > cv->c_xe)
1937 continue;
1938 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1939 if (y >= vp->v_ys && y <= vp->v_ye && xxe >= vp->v_xs && x1 <= vp->v_xe)
1940 break;
1941 if (vp)
1942 break;
1944 if (cv && cv->c_layer && x1 >= vp->v_xs && xxe <= vp->v_xe &&
1945 y - vp->v_yoff >= 0 && y - vp->v_yoff < cv->c_layer->l_height &&
1946 xxe - vp->v_xoff >= 0 && x1 - vp->v_xoff < cv->c_layer->l_width)
1948 struct layer *oldflayer = flayer;
1949 struct canvas *cvlist, *cvlnext;
1950 flayer = cv->c_layer;
1951 cvlist = flayer->l_cvlist;
1952 cvlnext = cv->c_lnext;
1953 flayer->l_cvlist = cv;
1954 cv->c_lnext = 0;
1955 LayClearLine(y - vp->v_yoff, x1 - vp->v_xoff, xxe - vp->v_xoff, bce);
1956 flayer->l_cvlist = cvlist;
1957 cv->c_lnext = cvlnext;
1958 flayer = oldflayer;
1959 continue;
1962 ClearLine((struct mline *)0, y, x1, xxe, bce);
1968 * if cur_only > 0, we only redisplay current line, as a full refresh is
1969 * too expensive over a low baud line.
1971 void
1972 Redisplay(cur_only)
1973 int cur_only;
1975 ASSERT(display);
1977 /* XXX do em all? */
1978 InsertMode(0);
1979 ChangeScrollRegion(0, D_height - 1);
1980 KeypadMode(0);
1981 CursorkeysMode(0);
1982 CursorVisibility(0);
1983 MouseMode(0);
1984 SetRendition(&mchar_null);
1985 SetFlow(FLOW_NOW);
1987 ClearAll();
1988 #ifdef RXVT_OSC
1989 RefreshXtermOSC();
1990 #endif
1991 if (cur_only > 0 && D_fore)
1992 RefreshArea(0, D_fore->w_y, D_width - 1, D_fore->w_y, 1);
1993 else
1994 RefreshAll(1);
1995 RefreshHStatus();
1996 CV_CALL(D_forecv, LayRestore();LaySetCursor());
1999 void
2000 RedisplayDisplays(cur_only)
2001 int cur_only;
2003 struct display *olddisplay = display;
2004 for (display = displays; display; display = display->d_next)
2005 Redisplay(cur_only);
2006 display = olddisplay;
2010 /* XXX: use oml! */
2011 void
2012 ScrollH(y, xs, xe, n, bce, oml)
2013 int y, xs, xe, n, bce;
2014 struct mline *oml;
2016 int i;
2018 if (n == 0)
2019 return;
2020 if (xe != D_width - 1)
2022 RefreshLine(y, xs, xe, 0);
2023 /* UpdateLine(oml, y, xs, xe); */
2024 return;
2026 GotoPos(xs, y);
2027 if (D_UT)
2028 SetRendition(&mchar_null);
2029 #ifdef COLOR
2030 if (D_BE)
2031 SetBackColor(bce);
2032 #endif
2033 if (n > 0)
2035 if (n >= xe - xs + 1)
2036 n = xe - xs + 1;
2037 if (D_CDC && !(n == 1 && D_DC))
2038 AddCStr2(D_CDC, n);
2039 else if (D_DC)
2041 for (i = n; i--; )
2042 AddCStr(D_DC);
2044 else
2046 RefreshLine(y, xs, xe, 0);
2047 /* UpdateLine(oml, y, xs, xe); */
2048 return;
2051 else
2053 if (-n >= xe - xs + 1)
2054 n = -(xe - xs + 1);
2055 if (!D_insert)
2057 if (D_CIC && !(n == -1 && D_IC))
2058 AddCStr2(D_CIC, -n);
2059 else if (D_IC)
2061 for (i = -n; i--; )
2062 AddCStr(D_IC);
2064 else if (D_IM)
2066 InsertMode(1);
2067 SetRendition(&mchar_null);
2068 #ifdef COLOR
2069 SetBackColor(bce);
2070 #endif
2071 for (i = -n; i--; )
2072 INSERTCHAR(' ');
2073 bce = 0; /* all done */
2075 else
2077 /* UpdateLine(oml, y, xs, xe); */
2078 RefreshLine(y, xs, xe, 0);
2079 return;
2082 else
2084 SetRendition(&mchar_null);
2085 #ifdef COLOR
2086 SetBackColor(bce);
2087 #endif
2088 for (i = -n; i--; )
2089 INSERTCHAR(' ');
2090 bce = 0; /* all done */
2093 if (bce && !D_BE)
2095 if (n > 0)
2096 ClearLine((struct mline *)0, y, xe - n + 1, xe, bce);
2097 else
2098 ClearLine((struct mline *)0, y, xs, xs - n - 1, bce);
2100 if (D_lp_missing && y == D_bot)
2102 if (n > 0)
2103 WriteLP(D_width - 1 - n, y);
2104 D_lp_missing = 0;
2108 void
2109 ScrollV(xs, ys, xe, ye, n, bce)
2110 int xs, ys, xe, ye, n, bce;
2112 int i;
2113 int up;
2114 int oldtop, oldbot;
2115 int alok, dlok, aldlfaster;
2116 int missy = 0;
2118 ASSERT(display);
2119 if (n == 0)
2120 return;
2121 if (n >= ye - ys + 1 || -n >= ye - ys + 1)
2123 ClearArea(xs, ys, xs, xe, xe, ye, bce, 0);
2124 return;
2126 if (xs > D_vpxmin || xe < D_vpxmax)
2128 RefreshArea(xs, ys, xe, ye, 0);
2129 return;
2132 if (D_lp_missing)
2134 if (D_bot > ye || D_bot < ys)
2135 missy = D_bot;
2136 else
2138 missy = D_bot - n;
2139 if (missy > ye || missy < ys)
2140 D_lp_missing = 0;
2144 up = 1;
2145 if (n < 0)
2147 up = 0;
2148 n = -n;
2150 if (n >= ye - ys + 1)
2151 n = ye - ys + 1;
2153 oldtop = D_top;
2154 oldbot = D_bot;
2155 if (ys < D_top || D_bot != ye)
2156 ChangeScrollRegion(ys, ye);
2157 alok = (D_AL || D_CAL || (ys >= D_top && ye == D_bot && up));
2158 dlok = (D_DL || D_CDL || (ys >= D_top && ye == D_bot && !up));
2159 if (D_top != ys && !(alok && dlok))
2160 ChangeScrollRegion(ys, ye);
2162 if (D_lp_missing &&
2163 (oldbot != D_bot ||
2164 (oldbot == D_bot && up && D_top == ys && D_bot == ye)))
2166 WriteLP(D_width - 1, oldbot);
2167 if (oldbot == D_bot) /* have scrolled */
2169 if (--n == 0)
2171 /* XXX
2172 ChangeScrollRegion(oldtop, oldbot);
2174 if (bce && !D_BE)
2175 ClearLine((struct mline *)0, ye, xs, xe, bce);
2176 return;
2181 if (D_UT)
2182 SetRendition(&mchar_null);
2183 #ifdef COLOR
2184 if (D_BE)
2185 SetBackColor(bce);
2186 #endif
2188 aldlfaster = (n > 1 && ys >= D_top && ye == D_bot && ((up && D_CDL) || (!up && D_CAL)));
2190 if ((up || D_SR) && D_top == ys && D_bot == ye && !aldlfaster)
2192 if (up)
2194 GotoPos(0, ye);
2195 for(i = n; i-- > 0; )
2196 AddCStr(D_NL); /* was SF, I think NL is faster */
2198 else
2200 GotoPos(0, ys);
2201 for(i = n; i-- > 0; )
2202 AddCStr(D_SR);
2205 else if (alok && dlok)
2207 if (up || ye != D_bot)
2209 GotoPos(0, up ? ys : ye+1-n);
2210 if (D_CDL && !(n == 1 && D_DL))
2211 AddCStr2(D_CDL, n);
2212 else
2213 for(i = n; i--; )
2214 AddCStr(D_DL);
2216 if (!up || ye != D_bot)
2218 GotoPos(0, up ? ye+1-n : ys);
2219 if (D_CAL && !(n == 1 && D_AL))
2220 AddCStr2(D_CAL, n);
2221 else
2222 for(i = n; i--; )
2223 AddCStr(D_AL);
2226 else
2228 RefreshArea(xs, ys, xe, ye, 0);
2229 return;
2231 if (bce && !D_BE)
2233 if (up)
2234 ClearArea(xs, ye - n + 1, xs, xe, xe, ye, bce, 0);
2235 else
2236 ClearArea(xs, ys, xs, xe, xe, ys + n - 1, bce, 0);
2238 if (D_lp_missing && missy != D_bot)
2239 WriteLP(D_width - 1, missy);
2240 /* XXX
2241 ChangeScrollRegion(oldtop, oldbot);
2242 if (D_lp_missing && missy != D_bot)
2243 WriteLP(D_width - 1, missy);
2247 void
2248 SetAttr(new)
2249 register int new;
2251 register int i, j, old, typ;
2253 if (!display || (old = D_rend.attr) == new)
2254 return;
2255 #ifdef COLORS16
2256 D_col16change = (old ^ new) & (A_BFG | A_BBG);
2257 new ^= D_col16change;
2258 if (old == new)
2259 return;
2260 #endif
2261 #if defined(TERMINFO) && defined(USE_SGR)
2262 if (D_SA)
2264 char *tparm();
2265 SetFont(ASCII);
2266 ospeed = D_dospeed;
2267 tputs(tparm(D_SA, new & A_SO, new & A_US, new & A_RV, new & A_BL,
2268 new & A_DI, new & A_BD, 0 , 0 ,
2269 0), 1, DoAddChar);
2270 D_rend.attr = new;
2271 D_atyp = 0;
2272 # ifdef COLOR
2273 if (D_hascolor)
2274 rend_setdefault(&D_rend);
2275 # endif
2276 return;
2278 #endif
2279 D_rend.attr = new;
2280 typ = D_atyp;
2281 if ((new & old) != old)
2283 if ((typ & ATYP_U))
2284 AddCStr(D_UE);
2285 if ((typ & ATYP_S))
2286 AddCStr(D_SE);
2287 if ((typ & ATYP_M))
2289 AddCStr(D_ME);
2290 #ifdef COLOR
2291 /* ansi attrib handling: \E[m resets color, too */
2292 if (D_hascolor)
2293 rend_setdefault(&D_rend);
2294 #endif
2295 #ifdef FONT
2296 if (!D_CG0)
2298 /* D_ME may also reset the alternate charset */
2299 D_rend.font = 0;
2300 # ifdef ENCODINGS
2301 D_realfont = 0;
2302 # endif
2304 #endif
2306 old = 0;
2307 typ = 0;
2309 old ^= new;
2310 for (i = 0, j = 1; old && i < NATTR; i++, j <<= 1)
2312 if ((old & j) == 0)
2313 continue;
2314 old ^= j;
2315 if (D_attrtab[i])
2317 AddCStr(D_attrtab[i]);
2318 typ |= D_attrtyp[i];
2321 D_atyp = typ;
2324 #ifdef FONT
2325 void
2326 SetFont(new)
2327 int new;
2329 int old = D_rend.font;
2330 if (!display || old == new)
2331 return;
2332 D_rend.font = new;
2333 #ifdef ENCODINGS
2334 if (D_encoding && CanEncodeFont(D_encoding, new))
2335 return;
2336 if (new == D_realfont)
2337 return;
2338 D_realfont = new;
2339 #endif
2340 if (D_xtable && D_xtable[(int)(unsigned char)new] &&
2341 D_xtable[(int)(unsigned char)new][256])
2343 AddCStr(D_xtable[(int)(unsigned char)new][256]);
2344 return;
2347 if (!D_CG0 && new != '0')
2349 new = ASCII;
2350 if (old == new)
2351 return;
2354 if (new == ASCII)
2355 AddCStr(D_CE0);
2356 #ifdef DW_CHARS
2357 else if (new < ' ')
2359 AddStr("\033$");
2360 if (new > 2)
2361 AddChar('(');
2362 AddChar(new + '@');
2364 #endif
2365 else
2366 AddCStr2(D_CS0, new);
2368 #endif
2370 #ifdef COLOR
2373 color256to16(jj)
2374 int jj;
2376 int min, max;
2377 int r, g, b;
2379 if (jj >= 232)
2381 jj = (jj - 232) / 6;
2382 jj = (jj & 1) << 3 | (jj & 2 ? 7 : 0);
2384 else if (jj >= 16)
2386 jj -= 16;
2387 r = jj / 36;
2388 g = (jj / 6) % 6;
2389 b = jj % 6;
2390 min = r < g ? (r < b ? r : b) : (g < b ? g : b);
2391 max = r > g ? (r > b ? r : b) : (g > b ? g : b);
2392 if (min == max)
2393 jj = ((max + 1) & 2) << 2 | ((max + 1) & 4 ? 7 : 0);
2394 else
2395 jj = (b - min) / (max - min) << 2 | (g - min) / (max - min) << 1 | (r -
2396 min) / (max - min) | (max > 3 ? 8 : 0);
2398 return jj;
2401 #ifdef COLORS256
2403 color256to88(jj)
2404 int jj;
2406 int r, g, b;
2408 if (jj >= 232)
2409 return (jj - 232) / 3 + 80;
2410 if (jj >= 16)
2412 jj -= 16;
2413 r = jj / 36;
2414 g = (jj / 6) % 6;
2415 b = jj % 6;
2416 return ((r + 1) / 2) * 16 + ((g + 1) / 2) * 4 + ((b + 1) / 2) + 16;
2418 return jj;
2420 #endif
2422 void
2423 SetColor(f, b)
2424 int f, b;
2426 int of, ob;
2427 static unsigned char sftrans[8] = {0,4,2,6,1,5,3,7};
2429 if (!display)
2430 return;
2432 of = rend_getfg(&D_rend);
2433 ob = rend_getbg(&D_rend);
2435 #ifdef COLORS16
2436 /* intense default not invented yet */
2437 if (f == 0x100)
2438 f = 0;
2439 if (b == 0x100)
2440 b = 0;
2441 #endif
2442 debug2("SetColor %d %d", coli2e(of), coli2e(ob));
2443 debug2(" -> %d %d\n", coli2e(f), coli2e(b));
2444 debug2("(%d %d", of, ob);
2445 debug2(" -> %d %d)\n", f, b);
2447 if (!D_CAX && D_hascolor && ((f == 0 && f != of) || (b == 0 && b != ob)))
2449 if (D_OP)
2450 AddCStr(D_OP);
2451 else
2453 int oattr;
2454 oattr = D_rend.attr;
2455 AddCStr(D_ME ? D_ME : "\033[m");
2456 #ifdef FONT
2457 if (D_ME && !D_CG0)
2459 /* D_ME may also reset the alternate charset */
2460 D_rend.font = 0;
2461 # ifdef ENCODINGS
2462 D_realfont = 0;
2463 # endif
2465 #endif
2466 D_atyp = 0;
2467 D_rend.attr = 0;
2468 SetAttr(oattr);
2470 of = ob = 0;
2472 rend_setfg(&D_rend, f);
2473 rend_setbg(&D_rend, b);
2474 #ifdef COLORS16
2475 D_col16change = 0;
2476 #endif
2477 if (!D_hascolor)
2478 return;
2479 f = f ? coli2e(f) : -1;
2480 b = b ? coli2e(b) : -1;
2481 of = of ? coli2e(of) : -1;
2482 ob = ob ? coli2e(ob) : -1;
2483 #ifdef COLORS256
2484 if (f != of && f > 15 && D_CCO != 256)
2485 f = D_CCO == 88 && D_CAF ? color256to88(f) : color256to16(f);
2486 if (f != of && f > 15 && D_CAF)
2488 AddCStr2(D_CAF, f);
2489 of = f;
2491 if (b != ob && b > 15 && D_CCO != 256)
2492 b = D_CCO == 88 && D_CAB ? color256to88(b) : color256to16(b);
2493 if (b != ob && b > 15 && D_CAB)
2495 AddCStr2(D_CAB, b);
2496 ob = b;
2498 #endif
2499 if (f != of && f != (of | 8))
2501 if (f == -1)
2502 AddCStr("\033[39m"); /* works because AX is set */
2503 else if (D_CAF)
2504 AddCStr2(D_CAF, f & 7);
2505 else if (D_CSF)
2506 AddCStr2(D_CSF, sftrans[f & 7]);
2508 if (b != ob && b != (ob | 8))
2510 if (b == -1)
2511 AddCStr("\033[49m"); /* works because AX is set */
2512 else if (D_CAB)
2513 AddCStr2(D_CAB, b & 7);
2514 else if (D_CSB)
2515 AddCStr2(D_CSB, sftrans[b & 7]);
2517 #ifdef COLORS16
2518 if (f != of && D_CXT && (f & 8) != 0 && f != -1)
2520 # ifdef TERMINFO
2521 AddCStr2("\033[9%p1%dm", f & 7);
2522 # else
2523 AddCStr2("\033[9%dm", f & 7);
2524 # endif
2526 if (b != ob && D_CXT && (b & 8) != 0 && b != -1)
2528 # ifdef TERMINFO
2529 AddCStr2("\033[10%p1%dm", b & 7);
2530 # else
2531 AddCStr2("\033[10%dm", b & 7);
2532 # endif
2534 #endif
2537 static void
2538 SetBackColor(new)
2539 int new;
2541 if (!display)
2542 return;
2543 SetColor(rend_getfg(&D_rend), new);
2545 #endif /* COLOR */
2547 void
2548 SetRendition(mc)
2549 struct mchar *mc;
2551 if (!display)
2552 return;
2553 #ifdef COLOR
2554 if (nattr2color && D_hascolor && (mc->attr & nattr2color) != 0)
2556 static struct mchar mmc;
2557 int i;
2558 mmc = *mc;
2559 for (i = 0; i < 8; i++)
2560 if (attr2color[i] && (mc->attr & (1 << i)) != 0)
2562 if (mc->color == 0 && attr2color[i][3])
2563 ApplyAttrColor(attr2color[i][3], &mmc);
2564 else if ((mc->color & 0x0f) == 0 && attr2color[i][2])
2565 ApplyAttrColor(attr2color[i][2], &mmc);
2566 else if ((mc->color & 0xf0) == 0 && attr2color[i][1])
2567 ApplyAttrColor(attr2color[i][1], &mmc);
2568 else
2569 ApplyAttrColor(attr2color[i][0], &mmc);
2571 mc = &mmc;
2572 debug2("SetRendition: mapped to %02x %02x\n", (unsigned char)mc->attr, 0x99 - (unsigned char)mc->color);
2574 # ifdef COLORS16
2575 if (D_hascolor && D_CC8 && (mc->attr & (A_BFG|A_BBG)))
2577 int a = mc->attr;
2578 if ((mc->attr & A_BFG) && D_MD)
2579 a |= A_BD;
2580 if ((mc->attr & A_BBG) && D_MB)
2581 a |= A_BL;
2582 if (D_rend.attr != a)
2583 SetAttr(a);
2585 else
2586 # endif /* COLORS16 */
2587 #endif /* COLOR */
2588 if (D_rend.attr != mc->attr)
2589 SetAttr(mc->attr);
2591 #ifdef COLOR
2592 if (D_rend.color != mc->color
2593 # ifdef COLORS256
2594 || D_rend.colorx != mc->colorx
2595 # endif
2596 # ifdef COLORS16
2597 || D_col16change
2598 # endif
2600 SetColor(rend_getfg(mc), rend_getbg(mc));
2601 #endif
2602 #ifdef FONT
2603 if (D_rend.font != mc->font)
2604 SetFont(mc->font);
2605 #endif
2608 void
2609 SetRenditionMline(ml, x)
2610 struct mline *ml;
2611 int x;
2613 if (!display)
2614 return;
2615 #ifdef COLOR
2616 if (nattr2color && D_hascolor && (ml->attr[x] & nattr2color) != 0)
2618 struct mchar mc;
2619 copy_mline2mchar(&mc, ml, x);
2620 SetRendition(&mc);
2621 return;
2623 # ifdef COLORS16
2624 if (D_hascolor && D_CC8 && (ml->attr[x] & (A_BFG|A_BBG)))
2626 int a = ml->attr[x];
2627 if ((ml->attr[x] & A_BFG) && D_MD)
2628 a |= A_BD;
2629 if ((ml->attr[x] & A_BBG) && D_MB)
2630 a |= A_BL;
2631 if (D_rend.attr != a)
2632 SetAttr(a);
2634 else
2635 # endif /* COLORS16 */
2636 #endif /* COLOR */
2637 if (D_rend.attr != ml->attr[x])
2638 SetAttr(ml->attr[x]);
2639 #ifdef COLOR
2640 if (D_rend.color != ml->color[x]
2641 # ifdef COLORS256
2642 || D_rend.colorx != ml->colorx[x]
2643 # endif
2644 # ifdef COLORS16
2645 || D_col16change
2646 # endif
2649 struct mchar mc;
2650 copy_mline2mchar(&mc, ml, x);
2651 SetColor(rend_getfg(&mc), rend_getbg(&mc));
2653 #endif
2654 #ifdef FONT
2655 if (D_rend.font != ml->font[x])
2656 SetFont(ml->font[x]);
2657 #endif
2660 void
2661 MakeStatus(msg)
2662 char *msg;
2664 register char *s, *t;
2665 register int max;
2667 if (!display)
2668 return;
2670 if (D_blocked)
2671 return;
2672 if (!D_tcinited)
2674 debug("tc not inited, just writing msg\n");
2675 if (D_processinputdata)
2676 return; /* XXX: better */
2677 AddStr(msg);
2678 AddStr("\r\n");
2679 Flush(0);
2680 return;
2682 if (!use_hardstatus || !D_HS)
2684 max = D_width;
2685 if (D_CLP == 0)
2686 max--;
2688 else
2689 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2690 if (D_status)
2692 /* same message? */
2693 if (strcmp(msg, D_status_lastmsg) == 0)
2695 debug("same message - increase timeout");
2696 if (!D_status_obufpos)
2697 SetTimeout(&D_statusev, MsgWait);
2698 return;
2700 RemoveStatusMinWait();
2702 for (s = t = msg; *s && t - msg < max; ++s)
2703 if (*s == BELL)
2704 AddCStr(D_BL);
2705 else if ((unsigned char)*s >= ' ' && *s != 0177)
2706 *t++ = *s;
2707 *t = '\0';
2708 if (t == msg)
2709 return;
2710 if (t - msg >= D_status_buflen)
2712 char *buf;
2713 if (D_status_lastmsg)
2714 buf = realloc(D_status_lastmsg, t - msg + 1);
2715 else
2716 buf = malloc(t - msg + 1);
2717 if (buf)
2719 D_status_lastmsg = buf;
2720 D_status_buflen = t - msg + 1;
2723 if (t - msg < D_status_buflen)
2724 strcpy(D_status_lastmsg, msg);
2725 D_status_len = t - msg;
2726 D_status_lastx = D_x;
2727 D_status_lasty = D_y;
2728 if (!use_hardstatus || D_has_hstatus == HSTATUS_IGNORE || D_has_hstatus == HSTATUS_MESSAGE)
2730 D_status = STATUS_ON_WIN;
2731 debug1("using STATLINE %d\n", STATLINE);
2732 GotoPos(0, STATLINE);
2733 SetRendition(&mchar_so);
2734 InsertMode(0);
2735 AddStr(msg);
2736 if (D_status_len < max)
2738 /* Wayne Davison: add extra space for readability */
2739 D_status_len++;
2740 SetRendition(&mchar_null);
2741 AddChar(' ');
2742 if (D_status_len < max)
2744 D_status_len++;
2745 AddChar(' ');
2746 AddChar('\b');
2748 AddChar('\b');
2750 D_x = -1;
2752 else
2754 D_status = STATUS_ON_HS;
2755 ShowHStatus(msg);
2758 D_status_obufpos = D_obufp - D_obuf;
2759 ASSERT(D_status_obufpos > 0);
2761 if (D_status == STATUS_ON_WIN)
2763 struct display *olddisplay = display;
2764 struct layer *oldflayer = flayer;
2766 /* this is copied over from RemoveStatus() */
2767 D_status = 0;
2768 GotoPos(0, STATLINE);
2769 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2770 GotoPos(D_status_lastx, D_status_lasty);
2771 flayer = D_forecv ? D_forecv->c_layer : 0;
2772 if (flayer)
2773 LaySetCursor();
2774 display = olddisplay;
2775 flayer = oldflayer;
2776 D_status = STATUS_ON_WIN;
2780 void
2781 RemoveStatus()
2783 struct display *olddisplay;
2784 struct layer *oldflayer;
2785 int where;
2787 if (!display)
2788 return;
2789 if (!(where = D_status))
2790 return;
2792 debug("RemoveStatus\n");
2793 if (D_status_obuffree >= 0)
2795 D_obuflen = D_status_obuflen;
2796 D_obuffree = D_status_obuffree;
2797 D_status_obuffree = -1;
2799 D_status = 0;
2800 D_status_obufpos = 0;
2801 D_status_bell = 0;
2802 evdeq(&D_statusev);
2803 olddisplay = display;
2804 oldflayer = flayer;
2805 if (where == STATUS_ON_WIN)
2807 if (captionalways || (D_canvas.c_slperp && D_canvas.c_slperp->c_slnext))
2809 GotoPos(0, STATLINE);
2810 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2811 GotoPos(D_status_lastx, D_status_lasty);
2814 else
2815 RefreshHStatus();
2816 flayer = D_forecv ? D_forecv->c_layer : 0;
2817 if (flayer)
2818 LaySetCursor();
2819 display = olddisplay;
2820 flayer = oldflayer;
2823 /* Remove the status but make sure that it is seen for MsgMinWait ms */
2824 static void
2825 RemoveStatusMinWait()
2827 /* XXX: should flush output first if D_status_obufpos is set */
2828 if (!D_status_bell && !D_status_obufpos)
2830 struct timeval now;
2831 int ti;
2832 gettimeofday(&now, NULL);
2833 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
2834 if (ti < MsgMinWait)
2835 DisplaySleep1000(MsgMinWait - ti, 0);
2837 RemoveStatus();
2840 /* refresh the display's hstatus line */
2841 void
2842 ShowHStatus(str)
2843 char *str;
2845 int l, ox, oy, max;
2847 if (D_status == STATUS_ON_WIN && D_has_hstatus == HSTATUS_LASTLINE && STATLINE == D_height-1)
2848 return; /* sorry, in use */
2849 if (D_blocked)
2850 return;
2852 if (D_HS && D_has_hstatus == HSTATUS_HS)
2854 if (!D_hstatus && (str == 0 || *str == 0))
2855 return;
2856 debug("ShowHStatus: using HS\n");
2857 SetRendition(&mchar_null);
2858 InsertMode(0);
2859 if (D_hstatus)
2860 AddCStr(D_DS);
2861 D_hstatus = 0;
2862 if (str == 0 || *str == 0)
2863 return;
2864 AddCStr2(D_TS, 0);
2865 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2866 if ((int)strlen(str) > max)
2867 AddStrn(str, max);
2868 else
2869 AddStr(str);
2870 AddCStr(D_FS);
2871 D_hstatus = 1;
2873 else if (D_has_hstatus == HSTATUS_LASTLINE)
2875 debug("ShowHStatus: using last line\n");
2876 ox = D_x;
2877 oy = D_y;
2878 str = str ? str : "";
2879 l = strlen(str);
2880 if (l > D_width)
2881 l = D_width;
2882 GotoPos(0, D_height - 1);
2883 SetRendition(captionalways || D_cvlist == 0 || D_cvlist->c_next ? &mchar_null: &mchar_so);
2884 PutWinMsg(str, 0, l);
2885 if (!captionalways && D_cvlist && !D_cvlist->c_next)
2886 while (l++ < D_width)
2887 PUTCHARLP(' ');
2888 if (l < D_width)
2889 ClearArea(l, D_height - 1, l, D_width - 1, D_width - 1, D_height - 1, 0, 0);
2890 if (ox != -1 && oy != -1)
2891 GotoPos(ox, oy);
2892 D_hstatus = *str ? 1 : 0;
2893 SetRendition(&mchar_null);
2895 else if (str && *str && D_has_hstatus == HSTATUS_MESSAGE)
2897 debug("ShowHStatus: using message\n");
2898 Msg(0, "%s", str);
2904 * Refreshes the harstatus of the fore window. Shouldn't be here...
2906 void
2907 RefreshHStatus()
2909 char *buf;
2911 evdeq(&D_hstatusev);
2912 if (D_status == STATUS_ON_HS)
2913 return;
2914 buf = MakeWinMsgEv(hstatusstring, D_fore, '%', (D_HS && D_has_hstatus == HSTATUS_HS && D_WS > 0) ? D_WS : D_width - !D_CLP, &D_hstatusev, 0);
2915 if (buf && *buf)
2917 ShowHStatus(buf);
2918 if (D_has_hstatus != HSTATUS_IGNORE && D_hstatusev.timeout.tv_sec)
2919 evenq(&D_hstatusev);
2921 else
2922 ShowHStatus((char *)0);
2925 /*********************************************************************/
2927 * Here come the routines that refresh an arbitrary part of the screen.
2930 void
2931 RefreshAll(isblank)
2932 int isblank;
2934 struct canvas *cv;
2936 ASSERT(display);
2937 debug("Signalling full refresh!\n");
2938 for (cv = D_cvlist; cv; cv = cv->c_next)
2940 CV_CALL(cv, LayRedisplayLine(-1, -1, -1, isblank));
2941 display = cv->c_display; /* just in case! */
2943 RefreshArea(0, 0, D_width - 1, D_height - 1, isblank);
2946 void
2947 RefreshArea(xs, ys, xe, ye, isblank)
2948 int xs, ys, xe, ye, isblank;
2950 int y;
2951 ASSERT(display);
2952 debug2("Refresh Area: %d,%d", xs, ys);
2953 debug3(" - %d,%d (isblank=%d)\n", xe, ye, isblank);
2954 if (!isblank && xs == 0 && xe == D_width - 1 && ye == D_height - 1 && (ys == 0 || D_CD))
2956 ClearArea(xs, ys, xs, xe, xe, ye, 0, 0);
2957 isblank = 1;
2959 for (y = ys; y <= ye; y++)
2960 RefreshLine(y, xs, xe, isblank);
2963 void
2964 RefreshLine(y, from, to, isblank)
2965 int y, from, to, isblank;
2967 struct viewport *vp, *lvp;
2968 struct canvas *cv, *lcv, *cvlist, *cvlnext;
2969 struct layer *oldflayer;
2970 int xx, yy, l;
2971 char *buf;
2972 struct win *p;
2974 ASSERT(display);
2976 debug2("RefreshLine %d %d", y, from);
2977 debug2(" %d %d\n", to, isblank);
2979 if (D_status == STATUS_ON_WIN && y == STATLINE)
2981 if (to >= D_status_len)
2982 D_status_len = to + 1;
2983 return; /* can't refresh status */
2986 /* The following check makes plenty of sense. Unfortunately,
2987 vte-based terminals (notably gnome-terminal) experience a quirk
2988 that causes the final line not to update properly when it falls outside
2989 the scroll region; clearing the line with D_CE avoids the glitch,
2990 so we'll disable this perfectly sensible shortcut until such a time
2991 as widespread vte installations lack the glitch.
2993 See http://bugzilla.gnome.org/show_bug.cgi?id=542087 for current
2994 status of the VTE bug report, and
2995 https://savannah.gnu.org/bugs/index.php?23699 for the history from
2996 the Savannah BTS. */
2997 #if 0
2998 if (y == D_height - 1 && D_has_hstatus == HSTATUS_LASTLINE)
3000 RefreshHStatus();
3001 return;
3003 #endif
3005 if (isblank == 0 && D_CE && to == D_width - 1 && from < to)
3007 GotoPos(from, y);
3008 if (D_UT || D_BE)
3009 SetRendition(&mchar_null);
3010 AddCStr(D_CE);
3011 isblank = 1;
3013 while (from <= to)
3015 lcv = 0;
3016 lvp = 0;
3017 for (cv = display->d_cvlist; cv; cv = cv->c_next)
3019 if (y == cv->c_ye + 1 && from >= cv->c_xs && from <= cv->c_xe)
3021 p = Layer2Window(cv->c_layer);
3022 buf = MakeWinMsgEv(captionstring, p, '%', cv->c_xe - cv->c_xs + (cv->c_xe + 1 < D_width || D_CLP), &cv->c_captev, 0);
3023 if (cv->c_captev.timeout.tv_sec)
3024 evenq(&cv->c_captev);
3025 xx = to > cv->c_xe ? cv->c_xe : to;
3026 l = strlen(buf);
3027 GotoPos(from, y);
3028 SetRendition(&mchar_so);
3029 if (l > xx - cv->c_xs + 1)
3030 l = xx - cv->c_xs + 1;
3031 PutWinMsg(buf, from - cv->c_xs, l);
3032 from = cv->c_xs + l;
3033 for (; from <= xx; from++)
3034 PUTCHARLP(' ');
3035 break;
3037 if (from == cv->c_xe + 1 && y >= cv->c_ys && y <= cv->c_ye + 1)
3039 GotoPos(from, y);
3040 SetRendition(&mchar_so);
3041 PUTCHARLP(' ');
3042 from++;
3043 break;
3045 if (y < cv->c_ys || y > cv->c_ye || to < cv->c_xs || from > cv->c_xe)
3046 continue;
3047 debug2("- canvas hit: %d %d", cv->c_xs, cv->c_ys);
3048 debug2(" %d %d\n", cv->c_xe, cv->c_ye);
3049 for (vp = cv->c_vplist; vp; vp = vp->v_next)
3051 debug2(" - vp: %d %d", vp->v_xs, vp->v_ys);
3052 debug2(" %d %d\n", vp->v_xe, vp->v_ye);
3053 /* find leftmost overlapping vp */
3054 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))
3056 lcv = cv;
3057 lvp = vp;
3061 if (cv)
3062 continue; /* we advanced from */
3063 if (lvp == 0)
3064 break;
3065 if (from < lvp->v_xs)
3067 if (!isblank)
3068 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xs - 1);
3069 from = lvp->v_xs;
3072 /* call LayRedisplayLine on canvas lcv viewport lvp */
3073 yy = y - lvp->v_yoff;
3074 xx = to < lvp->v_xe ? to : lvp->v_xe;
3076 if (lcv->c_layer && yy == lcv->c_layer->l_height)
3078 GotoPos(from, y);
3079 SetRendition(&mchar_blank);
3080 while (from <= lvp->v_xe && from - lvp->v_xoff < lcv->c_layer->l_width)
3082 PUTCHARLP('-');
3083 from++;
3085 if (from >= lvp->v_xe + 1)
3086 continue;
3088 if (lcv->c_layer == 0 || yy >= lcv->c_layer->l_height || from - lvp->v_xoff >= lcv->c_layer->l_width)
3090 if (!isblank)
3091 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xe);
3092 from = lvp->v_xe + 1;
3093 continue;
3096 if (xx - lvp->v_xoff >= lcv->c_layer->l_width)
3097 xx = lcv->c_layer->l_width + lvp->v_xoff - 1;
3098 oldflayer = flayer;
3099 flayer = lcv->c_layer;
3100 cvlist = flayer->l_cvlist;
3101 cvlnext = lcv->c_lnext;
3102 flayer->l_cvlist = lcv;
3103 lcv->c_lnext = 0;
3104 LayRedisplayLine(yy, from - lvp->v_xoff, xx - lvp->v_xoff, isblank);
3105 flayer->l_cvlist = cvlist;
3106 lcv->c_lnext = cvlnext;
3107 flayer = oldflayer;
3109 from = xx + 1;
3111 if (!isblank && from <= to)
3112 DisplayLine(&mline_null, &mline_blank, y, from, to);
3115 /*********************************************************************/
3117 /* clear lp_missing by writing the char on the screen. The
3118 * position must be safe.
3120 static void
3121 WriteLP(x2, y2)
3122 int x2, y2;
3124 struct mchar oldrend;
3126 ASSERT(display);
3127 ASSERT(D_lp_missing);
3128 oldrend = D_rend;
3129 debug2("WriteLP(%d,%d)\n", x2, y2);
3130 #ifdef DW_CHARS
3131 if (D_lpchar.mbcs)
3133 if (x2 > 0)
3134 x2--;
3135 else
3136 D_lpchar = mchar_blank;
3138 #endif
3139 /* Can't use PutChar */
3140 GotoPos(x2, y2);
3141 SetRendition(&D_lpchar);
3142 PUTCHAR(D_lpchar.image);
3143 #ifdef DW_CHARS
3144 if (D_lpchar.mbcs)
3145 PUTCHAR(D_lpchar.mbcs);
3146 #endif
3147 D_lp_missing = 0;
3148 SetRendition(&oldrend);
3151 void
3152 ClearLine(oml, y, from, to, bce)
3153 struct mline *oml;
3154 int from, to, y, bce;
3156 int x;
3157 #ifdef COLOR
3158 struct mchar bcechar;
3159 #endif
3161 debug3("ClearLine %d,%d-%d\n", y, from, to);
3162 if (D_UT) /* Safe to erase ? */
3163 SetRendition(&mchar_null);
3164 #ifdef COLOR
3165 if (D_BE)
3166 SetBackColor(bce);
3167 #endif
3168 if (from == 0 && D_CB && (to != D_width - 1 || (D_x == to && D_y == y)) && (!bce || D_BE))
3170 GotoPos(to, y);
3171 AddCStr(D_CB);
3172 return;
3174 if (to == D_width - 1 && D_CE && (!bce || D_BE))
3176 GotoPos(from, y);
3177 AddCStr(D_CE);
3178 return;
3180 if (oml == 0)
3181 oml = &mline_null;
3182 #ifdef COLOR
3183 if (!bce)
3185 DisplayLine(oml, &mline_blank, y, from, to);
3186 return;
3188 bcechar = mchar_blank;
3189 rend_setbg(&bcechar, bce);
3190 for (x = from; x <= to; x++)
3191 copy_mchar2mline(&bcechar, &mline_old, x);
3192 DisplayLine(oml, &mline_old, y, from, to);
3193 #else
3194 DisplayLine(oml, &mline_blank, y, from, to);
3195 #endif
3198 void
3199 DisplayLine(oml, ml, y, from, to)
3200 struct mline *oml, *ml;
3201 int from, to, y;
3203 register int x;
3204 int last2flag = 0, delete_lp = 0;
3206 ASSERT(display);
3207 ASSERT(y >= 0 && y < D_height);
3208 ASSERT(from >= 0 && from < D_width);
3209 ASSERT(to >= 0 && to < D_width);
3210 if (!D_CLP && y == D_bot && to == D_width - 1)
3212 if (D_lp_missing || !cmp_mline(oml, ml, to))
3214 #ifdef DW_CHARS
3215 if ((D_IC || D_IM) && from < to && !dw_left(ml, to, D_encoding))
3216 #else
3217 if ((D_IC || D_IM) && from < to)
3218 #endif
3220 last2flag = 1;
3221 D_lp_missing = 0;
3222 to--;
3224 else
3226 delete_lp = !cmp_mchar_mline(&mchar_blank, oml, to) && (D_CE || D_DC || D_CDC);
3227 D_lp_missing = !cmp_mchar_mline(&mchar_blank, ml, to);
3228 copy_mline2mchar(&D_lpchar, ml, to);
3231 to--;
3233 #ifdef DW_CHARS
3234 if (D_mbcs)
3236 /* finish dw-char (can happen after a wrap) */
3237 debug("DisplayLine finishing kanji\n");
3238 SetRenditionMline(ml, from);
3239 PUTCHAR(ml->image[from]);
3240 from++;
3242 #endif
3243 for (x = from; x <= to; x++)
3245 #if 0 /* no longer needed */
3246 if (x || D_x != D_width || D_y != y - 1)
3247 #endif
3249 if (x < to || x != D_width - 1 || ml->image[x + 1])
3250 if (cmp_mline(oml, ml, x))
3251 continue;
3252 GotoPos(x, y);
3254 #ifdef DW_CHARS
3255 if (dw_right(ml, x, D_encoding))
3257 x--;
3258 debug1("DisplayLine on right side of dw char- x now %d\n", x);
3259 GotoPos(x, y);
3261 if (x == to && dw_left(ml, x, D_encoding))
3262 break; /* don't start new kanji */
3263 #endif
3264 SetRenditionMline(ml, x);
3265 PUTCHAR(ml->image[x]);
3266 #ifdef DW_CHARS
3267 if (dw_left(ml, x, D_encoding))
3268 PUTCHAR(ml->image[++x]);
3269 #endif
3271 #if 0 /* not needed any longer */
3272 /* compare != 0 because ' ' can happen when clipping occures */
3273 if (to == D_width - 1 && y < D_height - 1 && D_x == D_width && ml->image[to + 1])
3274 GotoPos(0, y + 1);
3275 #endif
3276 if (last2flag)
3278 GotoPos(x, y);
3279 SetRenditionMline(ml, x + 1);
3280 PUTCHAR(ml->image[x + 1]);
3281 GotoPos(x, y);
3282 SetRenditionMline(ml, x);
3283 INSERTCHAR(ml->image[x]);
3285 else if (delete_lp)
3287 if (D_UT)
3288 SetRendition(&mchar_null);
3289 if (D_DC)
3290 AddCStr(D_DC);
3291 else if (D_CDC)
3292 AddCStr2(D_CDC, 1);
3293 else if (D_CE)
3294 AddCStr(D_CE);
3298 void
3299 PutChar(c, x, y)
3300 struct mchar *c;
3301 int x, y;
3303 GotoPos(x, y);
3304 SetRendition(c);
3305 PUTCHARLP(c->image);
3306 #ifdef DW_CHARS
3307 if (c->mbcs)
3309 # ifdef UTF8
3310 if (D_encoding == UTF8)
3311 D_rend.font = 0;
3312 # endif
3313 PUTCHARLP(c->mbcs);
3315 #endif
3318 void
3319 InsChar(c, x, xe, y, oml)
3320 struct mchar *c;
3321 int x, xe, y;
3322 struct mline *oml;
3324 GotoPos(x, y);
3325 if (y == D_bot && !D_CLP)
3327 if (x == D_width - 1)
3329 D_lp_missing = 1;
3330 D_lpchar = *c;
3331 return;
3333 if (xe == D_width - 1)
3334 D_lp_missing = 0;
3336 if (x == xe)
3338 SetRendition(c);
3339 PUTCHARLP(c->image);
3340 return;
3342 if (!(D_IC || D_CIC || D_IM) || xe != D_width - 1)
3344 RefreshLine(y, x, xe, 0);
3345 GotoPos(x + 1, y);
3346 /* UpdateLine(oml, y, x, xe); */
3347 return;
3349 InsertMode(1);
3350 if (!D_insert)
3352 #ifdef DW_CHARS
3353 if (c->mbcs && D_IC)
3354 AddCStr(D_IC);
3355 if (D_IC)
3356 AddCStr(D_IC);
3357 else
3358 AddCStr2(D_CIC, c->mbcs ? 2 : 1);
3359 #else
3360 if (D_IC)
3361 AddCStr(D_IC);
3362 else
3363 AddCStr2(D_CIC, 1);
3364 #endif
3366 SetRendition(c);
3367 RAW_PUTCHAR(c->image);
3368 #ifdef DW_CHARS
3369 if (c->mbcs)
3371 # ifdef UTF8
3372 if (D_encoding == UTF8)
3373 D_rend.font = 0;
3374 # endif
3375 if (D_x == D_width - 1)
3376 PUTCHARLP(c->mbcs);
3377 else
3378 RAW_PUTCHAR(c->mbcs);
3380 #endif
3383 void
3384 WrapChar(c, x, y, xs, ys, xe, ye, ins)
3385 struct mchar *c;
3386 int x, y;
3387 int xs, ys, xe, ye;
3388 int ins;
3390 int bce;
3392 #ifdef COLOR
3393 bce = rend_getbg(c);
3394 #else
3395 bce = 0;
3396 #endif
3397 debug("WrapChar:");
3398 debug2(" x %d y %d", x, y);
3399 debug2(" Dx %d Dy %d", D_x, D_y);
3400 debug2(" xs %d ys %d", xs, ys);
3401 debug3(" xe %d ye %d ins %d\n", xe, ye, ins);
3402 if (xs != 0 || x != D_width || !D_AM)
3404 if (y == ye)
3405 ScrollV(xs, ys, xe, ye, 1, bce);
3406 else if (y < D_height - 1)
3407 y++;
3408 if (ins)
3409 InsChar(c, xs, xe, y, 0);
3410 else
3411 PutChar(c, xs, y);
3412 return;
3414 if (y == ye) /* we have to scroll */
3416 debug("- scrolling\n");
3417 ChangeScrollRegion(ys, ye);
3418 if (D_bot != y || D_x != D_width || (!bce && !D_BE))
3420 debug("- have to call ScrollV\n");
3421 ScrollV(xs, ys, xe, ye, 1, bce);
3422 y--;
3425 else if (y == D_bot) /* remove unusable region? */
3426 ChangeScrollRegion(0, D_height - 1);
3427 if (D_x != D_width || D_y != y)
3429 if (D_CLP && y >= 0) /* don't even try if !LP */
3430 RefreshLine(y, D_width - 1, D_width - 1, 0);
3431 debug2("- refresh last char -> x,y now %d,%d\n", D_x, D_y);
3432 if (D_x != D_width || D_y != y) /* sorry, no bonus */
3434 if (y == ye)
3435 ScrollV(xs, ys, xe, ye, 1, bce);
3436 GotoPos(xs, y == ye || y == D_height - 1 ? y : y + 1);
3439 debug("- writeing new char");
3440 if (y != ye && y < D_height - 1)
3441 y++;
3442 if (ins != D_insert)
3443 InsertMode(ins);
3444 if (ins && !D_insert)
3446 InsChar(c, 0, xe, y, 0);
3447 debug2(" -> done with insert (%d,%d)\n", D_x, D_y);
3448 return;
3450 D_y = y;
3451 D_x = 0;
3452 SetRendition(c);
3453 RAW_PUTCHAR(c->image);
3454 #ifdef DW_CHARS
3455 if (c->mbcs)
3457 # ifdef UTF8
3458 if (D_encoding == UTF8)
3459 D_rend.font = 0;
3460 # endif
3461 RAW_PUTCHAR(c->mbcs);
3463 #endif
3464 debug2(" -> done (%d,%d)\n", D_x, D_y);
3468 ResizeDisplay(wi, he)
3469 int wi, he;
3471 ASSERT(display);
3472 debug2("ResizeDisplay: to (%d,%d).\n", wi, he);
3473 if (D_width == wi && D_height == he)
3475 debug("ResizeDisplay: No change\n");
3476 return 0;
3478 if (D_width != wi && (D_height == he || !D_CWS) && D_CZ0 && (wi == Z0width || wi == Z1width))
3480 debug("ResizeDisplay: using Z0/Z1\n");
3481 AddCStr(wi == Z0width ? D_CZ0 : D_CZ1);
3482 ChangeScreenSize(wi, D_height, 0);
3483 return (he == D_height) ? 0 : -1;
3485 if (D_CWS)
3487 debug("ResizeDisplay: using WS\n");
3488 AddCStr(tgoto(D_CWS, wi, he));
3489 ChangeScreenSize(wi, he, 0);
3490 return 0;
3492 return -1;
3495 void
3496 ChangeScrollRegion(newtop, newbot)
3497 int newtop, newbot;
3499 if (display == 0)
3500 return;
3501 if (newtop == newbot)
3502 return; /* xterm etc can't do it */
3503 if (newtop == -1)
3504 newtop = 0;
3505 if (newbot == -1)
3506 newbot = D_height - 1;
3507 if (D_CS == 0)
3509 D_top = 0;
3510 D_bot = D_height - 1;
3511 return;
3513 if (D_top == newtop && D_bot == newbot)
3514 return;
3515 debug2("ChangeScrollRegion: (%d - %d)\n", newtop, newbot);
3516 AddCStr(tgoto(D_CS, newbot, newtop));
3517 D_top = newtop;
3518 D_bot = newbot;
3519 D_y = D_x = -1; /* Just in case... */
3522 #ifdef RXVT_OSC
3523 void
3524 SetXtermOSC(i, s)
3525 int i;
3526 char *s;
3528 static char oscs[] = "0;\000\00020;\00039;\00049;\000";
3530 ASSERT(display);
3531 if (!D_CXT)
3532 return;
3533 if (!s)
3534 s = "";
3535 if (!D_xtermosc[i] && !*s)
3536 return;
3537 if (i == 0 && !*s)
3538 s = "screen"; /* always set icon name */
3539 if (i == 1 && !*s)
3540 s = ""; /* no background */
3541 if (i == 2 && !*s)
3542 s = "black"; /* black text */
3543 if (i == 3 && !*s)
3544 s = "white"; /* on white background */
3545 D_xtermosc[i] = 1;
3546 AddStr("\033]");
3547 AddStr(oscs + i * 4);
3548 AddStr(s);
3549 AddChar(7);
3552 void
3553 ClearAllXtermOSC()
3555 int i;
3556 for (i = 3; i >= 0; i--)
3557 SetXtermOSC(i, 0);
3559 #endif
3562 * Output buffering routines
3565 void
3566 AddStr(str)
3567 char *str;
3569 register char c;
3571 ASSERT(display);
3573 #ifdef UTF8
3574 if (D_encoding == UTF8)
3576 while ((c = *str++))
3577 AddUtf8((unsigned char)c);
3578 return;
3580 #endif
3581 while ((c = *str++))
3582 AddChar(c);
3585 void
3586 AddStrn(str, n)
3587 char *str;
3588 int n;
3590 register char c;
3592 ASSERT(display);
3593 #ifdef UTF8
3594 if (D_encoding == UTF8)
3596 while ((c = *str++) && n-- > 0)
3597 AddUtf8((unsigned char)c);
3599 else
3600 #endif
3601 while ((c = *str++) && n-- > 0)
3602 AddChar(c);
3603 while (n-- > 0)
3604 AddChar(' ');
3607 void
3608 Flush(progress)
3609 int progress;
3611 register int l;
3612 int wr;
3613 register char *p;
3615 ASSERT(display);
3616 l = D_obufp - D_obuf;
3617 debug1("Flush(): %d\n", l);
3618 if (l == 0)
3619 return;
3620 ASSERT(l + D_obuffree == D_obuflen);
3621 if (D_userfd < 0)
3623 D_obuffree += l;
3624 D_obufp = D_obuf;
3625 return;
3627 p = D_obuf;
3628 if (!progress)
3630 if (fcntl(D_userfd, F_SETFL, 0))
3631 debug1("Warning: BLOCK fcntl failed: %d\n", errno);
3633 while (l)
3635 if (progress)
3637 fd_set w;
3638 FD_ZERO(&w);
3639 FD_SET(D_userfd, &w);
3640 struct timeval t;
3641 t.tv_sec = progress;
3642 t.tv_usec = 0;
3643 wr = select(FD_SETSIZE, (fd_set *)0, &w, (fd_set *)0, &t);
3644 if (wr == -1)
3646 if (errno == EINTR)
3647 continue;
3648 debug1("Warning: select failed: %d\n", errno);
3649 break;
3651 if (wr == 0)
3653 /* no progress after 3 seconds. sorry. */
3654 debug1("Warning: no progress after %d seconds\n", progress);
3655 break;
3658 wr = write(D_userfd, p, l);
3659 if (wr <= 0)
3661 if (errno == EINTR)
3662 continue;
3663 debug1("Writing to display: %d\n", errno);
3664 break;
3666 D_obuffree += wr;
3667 p += wr;
3668 l -= wr;
3670 if (l)
3671 debug1("Warning: Flush could not write %d bytes\n", l);
3672 D_obuffree += l;
3673 D_obufp = D_obuf;
3674 if (!progress)
3676 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
3677 debug1("Warning: NBLOCK fcntl failed: %d\n", errno);
3679 if (D_blocked == 1)
3680 D_blocked = 0;
3681 D_blocked_fuzz = 0;
3684 void
3685 freetty()
3687 if (D_userfd >= 0)
3688 close(D_userfd);
3689 debug1("did freetty %d\n", D_userfd);
3690 D_userfd = -1;
3691 D_obufp = 0;
3692 D_obuffree = 0;
3693 if (D_obuf)
3694 free(D_obuf);
3695 D_obuf = 0;
3696 D_obuflen = 0;
3697 D_obuflenmax = -D_obufmax;
3698 D_blocked = 0;
3699 D_blocked_fuzz = 0;
3703 * Asynchronous output routines by
3704 * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
3707 void
3708 Resize_obuf()
3710 register int ind;
3712 ASSERT(display);
3713 if (D_status_obuffree >= 0)
3715 ASSERT(D_obuffree == -1);
3716 RemoveStatusMinWait();
3717 if (--D_obuffree > 0) /* redo AddChar decrement */
3718 return;
3720 if (D_obuflen && D_obuf)
3722 ind = D_obufp - D_obuf;
3723 D_obuflen += GRAIN;
3724 D_obuffree += GRAIN;
3725 D_obuf = realloc(D_obuf, D_obuflen);
3727 else
3729 ind = 0;
3730 D_obuflen = GRAIN;
3731 D_obuffree = GRAIN;
3732 D_obuf = malloc(D_obuflen);
3734 if (!D_obuf)
3735 Panic(0, "Out of memory");
3736 D_obufp = D_obuf + ind;
3737 D_obuflenmax = D_obuflen - D_obufmax;
3738 debug1("ResizeObuf: resized to %d\n", D_obuflen);
3741 void
3742 DisplaySleep1000(n, eat)
3743 int n;
3744 int eat;
3746 char buf;
3747 fd_set r;
3748 struct timeval t;
3750 if (n <= 0)
3751 return;
3752 if (!display)
3754 debug("DisplaySleep has no display sigh\n");
3755 sleep1000(n);
3756 return;
3758 t.tv_usec = (n % 1000) * 1000;
3759 t.tv_sec = n / 1000;
3760 FD_ZERO(&r);
3761 FD_SET(D_userfd, &r);
3762 if (select(FD_SETSIZE, &r, (fd_set *)0, (fd_set *)0, &t) > 0)
3764 debug("display activity stopped sleep\n");
3765 if (eat)
3766 read(D_userfd, &buf, 1);
3768 debug2("DisplaySleep(%d) ending, eat was %d\n", n, eat);
3771 #ifdef AUTO_NUKE
3772 void
3773 NukePending()
3774 {/* Nuke pending output in current display, clear screen */
3775 register int len;
3776 int oldtop = D_top, oldbot = D_bot;
3777 struct mchar oldrend;
3778 int oldkeypad = D_keypad, oldcursorkeys = D_cursorkeys;
3779 int oldcurvis = D_curvis;
3780 int oldmouse = D_mouse;
3782 oldrend = D_rend;
3783 len = D_obufp - D_obuf;
3784 debug1("NukePending: nuking %d chars\n", len);
3786 /* Throw away any output that we can... */
3787 # ifdef POSIX
3788 tcflush(D_userfd, TCOFLUSH);
3789 # else
3790 # ifdef TCFLSH
3791 (void) ioctl(D_userfd, TCFLSH, (char *) 1);
3792 # endif
3793 # endif
3795 D_obufp = D_obuf;
3796 D_obuffree += len;
3797 D_top = D_bot = -1;
3798 AddCStr(D_IS);
3799 AddCStr(D_TI);
3800 /* Turn off all attributes. (Tim MacKenzie) */
3801 if (D_ME)
3802 AddCStr(D_ME);
3803 else
3805 #ifdef COLOR
3806 if (D_hascolor)
3807 AddStr("\033[m"); /* why is D_ME not set? */
3808 #endif
3809 AddCStr(D_SE);
3810 AddCStr(D_UE);
3812 /* Check for toggle */
3813 if (D_IM && strcmp(D_IM, D_EI))
3814 AddCStr(D_EI);
3815 D_insert = 0;
3816 /* Check for toggle */
3817 #ifdef MAPKEYS
3818 if (D_KS && strcmp(D_KS, D_KE))
3819 AddCStr(D_KS);
3820 if (D_CCS && strcmp(D_CCS, D_CCE))
3821 AddCStr(D_CCS);
3822 #else
3823 if (D_KS && strcmp(D_KS, D_KE))
3824 AddCStr(D_KE);
3825 D_keypad = 0;
3826 if (D_CCS && strcmp(D_CCS, D_CCE))
3827 AddCStr(D_CCE);
3828 D_cursorkeys = 0;
3829 #endif
3830 AddCStr(D_CE0);
3831 D_rend = mchar_null;
3832 D_atyp = 0;
3833 AddCStr(D_DS);
3834 D_hstatus = 0;
3835 AddCStr(D_VE);
3836 D_curvis = 0;
3837 ChangeScrollRegion(oldtop, oldbot);
3838 SetRendition(&oldrend);
3839 KeypadMode(oldkeypad);
3840 CursorkeysMode(oldcursorkeys);
3841 CursorVisibility(oldcurvis);
3842 MouseMode(oldmouse);
3843 if (D_CWS)
3845 debug("ResizeDisplay: using WS\n");
3846 AddCStr(tgoto(D_CWS, D_width, D_height));
3848 else if (D_CZ0 && (D_width == Z0width || D_width == Z1width))
3850 debug("ResizeDisplay: using Z0/Z1\n");
3851 AddCStr(D_width == Z0width ? D_CZ0 : D_CZ1);
3854 #endif /* AUTO_NUKE */
3856 #ifdef linux
3857 /* linux' select can't handle flow control, so wait 100ms if
3858 * we get EAGAIN
3860 static void
3861 disp_writeev_eagain(ev, data)
3862 struct event *ev;
3863 char *data;
3865 display = (struct display *)data;
3866 evdeq(&D_writeev);
3867 D_writeev.type = EV_WRITE;
3868 D_writeev.handler = disp_writeev_fn;
3869 evenq(&D_writeev);
3871 #endif
3873 static void
3874 disp_writeev_fn(ev, data)
3875 struct event *ev;
3876 char *data;
3878 int len, size = OUTPUT_BLOCK_SIZE;
3880 display = (struct display *)data;
3881 len = D_obufp - D_obuf;
3882 if (len < size)
3883 size = len;
3884 if (D_status_obufpos && size > D_status_obufpos)
3885 size = D_status_obufpos;
3886 ASSERT(len >= 0);
3887 size = write(D_userfd, D_obuf, size);
3888 if (size >= 0)
3890 len -= size;
3891 if (len)
3893 bcopy(D_obuf + size, D_obuf, len);
3894 debug2("ASYNC: wrote %d - remaining %d\n", size, len);
3896 D_obufp -= size;
3897 D_obuffree += size;
3898 if (D_status_obufpos)
3900 D_status_obufpos -= size;
3901 if (!D_status_obufpos)
3903 debug("finished writing the status message\n");
3904 /* we're finished displaying the message! */
3905 if (D_status == STATUS_ON_WIN)
3907 /* setup continue trigger */
3908 D_status_obuflen = D_obuflen;
3909 D_status_obuffree = D_obuffree;
3910 /* setting obbuffree to 0 will make AddChar call
3911 * ResizeObuf */
3912 D_obuffree = D_obuflen = 0;
3914 gettimeofday(&D_status_time, NULL);
3915 SetTimeout(&D_statusev, MsgWait);
3916 evenq(&D_statusev);
3917 #ifdef HAVE_BRAILLE
3918 RefreshBraille(); /* let user see multiple Msg()s */
3919 #endif
3922 if (D_blocked_fuzz)
3924 D_blocked_fuzz -= size;
3925 if (D_blocked_fuzz < 0)
3926 D_blocked_fuzz = 0;
3928 if (D_blockedev.queued)
3930 if (D_obufp - D_obuf > D_obufmax / 2)
3932 debug2("%s: resetting timeout to %g secs\n", D_usertty, D_nonblock/1000.);
3933 SetTimeout(&D_blockedev, D_nonblock);
3935 else
3937 debug1("%s: deleting blocked timeout\n", D_usertty);
3938 evdeq(&D_blockedev);
3941 if (D_blocked == 1 && D_obuf == D_obufp)
3943 /* empty again, restart output */
3944 debug1("%s: buffer empty, unblocking\n", D_usertty);
3945 D_blocked = 0;
3946 Activate(D_fore ? D_fore->w_norefresh : 0);
3947 D_blocked_fuzz = D_obufp - D_obuf;
3950 else
3952 #ifdef linux
3953 /* linux flow control is badly broken */
3954 if (errno == EAGAIN)
3956 evdeq(&D_writeev);
3957 D_writeev.type = EV_TIMEOUT;
3958 D_writeev.handler = disp_writeev_eagain;
3959 SetTimeout(&D_writeev, 100);
3960 evenq(&D_writeev);
3962 #endif
3963 if (errno != EINTR && errno != EAGAIN)
3964 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3965 if (errno != EWOULDBLOCK)
3966 #endif
3967 Msg(errno, "Error writing output to display");
3971 static void
3972 disp_readev_fn(ev, data)
3973 struct event *ev;
3974 char *data;
3976 int size;
3977 char buf[IOSIZE];
3978 struct canvas *cv;
3980 display = (struct display *)data;
3982 /* Hmmmm... a bit ugly... */
3983 if (D_forecv)
3984 for (cv = D_forecv->c_layer->l_cvlist; cv; cv = cv->c_lnext)
3986 display = cv->c_display;
3987 if (D_status == STATUS_ON_WIN)
3988 RemoveStatus();
3991 display = (struct display *)data;
3992 if (D_fore == 0)
3993 size = IOSIZE;
3994 else
3996 #ifdef PSEUDOS
3997 if (W_UWP(D_fore))
3998 size = sizeof(D_fore->w_pwin->p_inbuf) - D_fore->w_pwin->p_inlen;
3999 else
4000 #endif
4001 size = sizeof(D_fore->w_inbuf) - D_fore->w_inlen;
4004 if (size > IOSIZE)
4005 size = IOSIZE;
4006 if (size <= 0)
4007 size = 1; /* Always allow one char for command keys */
4009 size = read(D_userfd, buf, size);
4010 if (size < 0)
4012 if (errno == EINTR || errno == EAGAIN)
4013 return;
4014 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
4015 if (errno == EWOULDBLOCK)
4016 return;
4017 #endif
4018 debug1("Read error: %d - hangup!\n", errno);
4019 Hangup();
4020 sleep(1);
4021 return;
4023 else if (size == 0)
4025 debug("Found EOF - hangup!\n");
4026 Hangup();
4027 sleep(1);
4028 return;
4030 if (D_blocked == 4)
4032 D_blocked = 0;
4033 #ifdef BLANKER_PRG
4034 KillBlanker();
4035 #endif
4036 Activate(D_fore ? D_fore->w_norefresh : 0);
4037 ResetIdle();
4038 return;
4040 #ifdef ZMODEM
4041 if (D_blocked > 1) /* 2, 3 */
4043 char *bufp;
4044 struct win *p;
4046 flayer = 0;
4047 for (p = windows; p ; p = p->w_next)
4048 if (p->w_zdisplay == display)
4050 flayer = &p->w_layer;
4051 bufp = buf;
4052 while (size > 0)
4053 LayProcess(&bufp, &size);
4054 return;
4056 debug("zmodem window gone, deblocking display");
4057 zmodem_abort(0, display);
4059 #endif
4060 if (idletimo > 0)
4061 ResetIdle();
4062 if (D_fore)
4063 D_fore->w_lastdisp = display;
4064 if (D_mouse && D_forecv)
4066 unsigned char *bp = (unsigned char *)buf;
4067 int x, y, i = size;
4069 /* XXX this assumes that the string is read in as a whole... */
4070 for (i = size; i > 0; i--, bp++)
4072 if (i > 5 && bp[0] == 033 && bp[1] == '[' && bp[2] == 'M')
4074 bp++;
4075 i--;
4077 else if (i < 5 || bp[0] != 0233 || bp[1] != 'M')
4078 continue;
4079 x = bp[3] - 33;
4080 y = bp[4] - 33;
4081 if (x >= D_forecv->c_xs && x <= D_forecv->c_xe && y >= D_forecv->c_ys && y <= D_forecv->c_ye)
4083 if (D_fore && D_fore->w_mouse)
4085 /* Send clicks only if the window is expecting clicks */
4086 x -= D_forecv->c_xoff;
4087 y -= D_forecv->c_yoff;
4088 if (x >= 0 && x < D_forecv->c_layer->l_width && y >= 0 && y < D_forecv->c_layer->l_height)
4090 bp[3] = x + 33;
4091 bp[4] = y + 33;
4092 i -= 4;
4093 bp += 4;
4094 continue;
4098 else if (D_mousetrack && bp[2] == '#')
4100 /* 'focus' to the clicked region, only on mouse up */
4101 struct canvas *cv = FindCanvas(x, y);
4102 if (cv)
4104 SetForeCanvas(display, cv);
4105 /* XXX: Do we want to reset the input buffer? */
4108 if (bp[0] == '[')
4110 bcopy((char *)bp + 1, (char *)bp, i);
4111 bp--;
4112 size--;
4114 if (i > 5)
4115 bcopy((char *)bp + 5, (char *)bp, i - 5);
4116 bp--;
4117 i -= 4;
4118 size -= 5;
4121 #ifdef ENCODINGS
4122 if (D_encoding != (D_forecv ? D_forecv->c_layer->l_encoding : 0))
4124 int i, j, c, enc;
4125 char buf2[IOSIZE * 2 + 10];
4126 enc = D_forecv ? D_forecv->c_layer->l_encoding : 0;
4127 for (i = j = 0; i < size; i++)
4129 c = ((unsigned char *)buf)[i];
4130 c = DecodeChar(c, D_encoding, &D_decodestate);
4131 if (c == -2)
4132 i--; /* try char again */
4133 if (c < 0)
4134 continue;
4135 if (pastefont)
4137 int font = 0;
4138 j += EncodeChar(buf2 + j, c, enc, &font);
4139 j += EncodeChar(buf2 + j, -1, enc, &font);
4141 else
4142 j += EncodeChar(buf2 + j, c, enc, 0);
4143 if (j > (int)sizeof(buf2) - 10) /* just in case... */
4144 break;
4146 (*D_processinput)(buf2, j);
4147 return;
4149 #endif
4150 (*D_processinput)(buf, size);
4153 static void
4154 disp_status_fn(ev, data)
4155 struct event *ev;
4156 char *data;
4158 display = (struct display *)data;
4159 debug1("disp_status_fn for display %x\n", (int)display);
4160 if (D_status)
4161 RemoveStatus();
4164 static void
4165 disp_hstatus_fn(ev, data)
4166 struct event *ev;
4167 char *data;
4169 display = (struct display *)data;
4170 if (D_status == STATUS_ON_HS)
4172 SetTimeout(ev, 1);
4173 evenq(ev);
4174 return;
4176 RefreshHStatus();
4179 static void
4180 disp_blocked_fn(ev, data)
4181 struct event *ev;
4182 char *data;
4184 struct win *p;
4186 display = (struct display *)data;
4187 debug1("blocked timeout %s\n", D_usertty);
4188 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
4190 debug("stopping output to display\n");
4191 D_blocked = 1;
4192 /* re-enable all windows */
4193 for (p = windows; p; p = p->w_next)
4194 if (p->w_readev.condneg == &D_obuflenmax)
4196 debug1("freeing window #%d\n", p->w_number);
4197 p->w_readev.condpos = p->w_readev.condneg = 0;
4202 static void
4203 cv_winid_fn(ev, data)
4204 struct event *ev;
4205 char *data;
4207 int ox, oy;
4208 struct canvas *cv = (struct canvas *)data;
4210 display = cv->c_display;
4211 if (D_status == STATUS_ON_WIN)
4213 SetTimeout(ev, 1);
4214 evenq(ev);
4215 return;
4217 ox = D_x;
4218 oy = D_y;
4219 if (cv->c_ye + 1 < D_height)
4220 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
4221 if (ox != -1 && oy != -1)
4222 GotoPos(ox, oy);
4225 #ifdef MAPKEYS
4226 static void
4227 disp_map_fn(ev, data)
4228 struct event *ev;
4229 char *data;
4231 char *p;
4232 int l, i;
4233 unsigned char *q;
4234 display = (struct display *)data;
4235 debug("Flushing map sequence\n");
4236 if (!(l = D_seql))
4237 return;
4238 p = (char *)D_seqp - l;
4239 D_seqp = D_kmaps + 3;
4240 D_seql = 0;
4241 if ((q = D_seqh) != 0)
4243 D_seqh = 0;
4244 i = q[0] << 8 | q[1];
4245 i &= ~KMAP_NOTIMEOUT;
4246 debug1("Mapping former hit #%d - ", i);
4247 debug2("%d(%s) - ", q[2], q + 3);
4248 if (StuffKey(i))
4249 ProcessInput2((char *)q + 3, q[2]);
4250 if (display == 0)
4251 return;
4252 l -= q[2];
4253 p += q[2];
4255 else
4256 D_dontmap = 1;
4257 ProcessInput(p, l);
4259 #endif
4261 static void
4262 disp_idle_fn(ev, data)
4263 struct event *ev;
4264 char *data;
4266 struct display *olddisplay;
4267 display = (struct display *)data;
4268 debug("idle timeout\n");
4269 if (idletimo <= 0 || idleaction.nr == RC_ILLEGAL)
4270 return;
4271 olddisplay = display;
4272 flayer = D_forecv->c_layer;
4273 fore = D_fore;
4274 DoAction(&idleaction, -1);
4275 if (idleaction.nr == RC_BLANKER)
4276 return;
4277 for (display = displays; display; display = display->d_next)
4278 if (olddisplay == display)
4279 break;
4280 if (display)
4281 ResetIdle();
4284 void
4285 ResetIdle()
4287 if (idletimo > 0)
4289 SetTimeout(&D_idleev, idletimo);
4290 if (!D_idleev.queued)
4291 evenq(&D_idleev);
4293 else
4294 evdeq(&D_idleev);
4298 #ifdef BLANKER_PRG
4300 static void
4301 disp_blanker_fn(ev, data)
4302 struct event *ev;
4303 char *data;
4305 char buf[IOSIZE], *b;
4306 int size;
4308 display = (struct display *)data;
4309 size = read(D_blankerev.fd, buf, IOSIZE);
4310 if (size <= 0)
4312 evdeq(&D_blankerev);
4313 close(D_blankerev.fd);
4314 D_blankerev.fd = -1;
4315 return;
4317 for (b = buf; size; size--)
4318 AddChar(*b++);
4321 void
4322 KillBlanker()
4324 int oldtop = D_top, oldbot = D_bot;
4325 struct mchar oldrend;
4327 if (D_blankerev.fd == -1)
4328 return;
4329 if (D_blocked == 4)
4330 D_blocked = 0;
4331 evdeq(&D_blankerev);
4332 close(D_blankerev.fd);
4333 D_blankerev.fd = -1;
4334 Kill(D_blankerpid, SIGHUP);
4335 D_top = D_bot = -1;
4336 oldrend = D_rend;
4337 if (D_ME)
4339 AddCStr(D_ME);
4340 AddCStr(D_ME);
4342 else
4344 #ifdef COLOR
4345 if (D_hascolor)
4346 AddStr("\033[m\033[m"); /* why is D_ME not set? */
4347 #endif
4348 AddCStr(D_SE);
4349 AddCStr(D_UE);
4351 AddCStr(D_VE);
4352 AddCStr(D_CE0);
4353 D_rend = mchar_null;
4354 D_atyp = 0;
4355 D_curvis = 0;
4356 D_x = D_y = -1;
4357 ChangeScrollRegion(oldtop, oldbot);
4358 SetRendition(&oldrend);
4359 ClearAll();
4362 void
4363 RunBlanker(cmdv)
4364 char **cmdv;
4366 char *m;
4367 int pid;
4368 int slave = -1;
4369 char termname[30];
4370 #ifndef TIOCSWINSZ
4371 char libuf[20], cobuf[20];
4372 #endif
4373 char **np;
4375 strcpy(termname, "TERM=");
4376 strncpy(termname + 5, D_termname, sizeof(termname) - 6);
4377 termname[sizeof(termname) - 1] = 0;
4378 KillBlanker();
4379 D_blankerpid = -1;
4380 if ((D_blankerev.fd = OpenPTY(&m)) == -1)
4382 Msg(0, "OpenPty failed");
4383 return;
4385 #ifdef O_NOCTTY
4386 if (pty_preopen)
4388 if ((slave = open(m, O_RDWR|O_NOCTTY)) == -1)
4390 Msg(errno, "%s", m);
4391 close(D_blankerev.fd);
4392 D_blankerev.fd = -1;
4393 return;
4396 #endif
4397 switch (pid = (int)fork())
4399 case -1:
4400 Msg(errno, "fork");
4401 close(D_blankerev.fd);
4402 D_blankerev.fd = -1;
4403 return;
4404 case 0:
4405 displays = 0;
4406 #ifdef DEBUG
4407 if (dfp && dfp != stderr)
4409 fclose(dfp);
4410 dfp = 0;
4412 #endif
4413 if (setgid(real_gid) || setuid(real_uid))
4414 Panic(errno, "setuid/setgid");
4415 brktty(D_userfd);
4416 freetty();
4417 close(0);
4418 close(1);
4419 close(2);
4420 closeallfiles(slave);
4421 if (open(m, O_RDWR))
4422 Panic(errno, "Cannot open %s", m);
4423 dup(0);
4424 dup(0);
4425 if (slave != -1)
4426 close(slave);
4427 InitPTY(0);
4428 fgtty(0);
4429 SetTTY(0, &D_OldMode);
4430 np = NewEnv + 3;
4431 *np++ = NewEnv[0];
4432 *np++ = termname;
4433 #ifdef TIOCSWINSZ
4434 glwz.ws_col = D_width;
4435 glwz.ws_row = D_height;
4436 (void)ioctl(0, TIOCSWINSZ, (char *)&glwz);
4437 #else
4438 sprintf(libuf, "LINES=%d", D_height);
4439 sprintf(cobuf, "COLUMNS=%d", D_width);
4440 *np++ = libuf;
4441 *np++ = cobuf;
4442 #endif
4443 #ifdef SIGPIPE
4444 signal(SIGPIPE, SIG_DFL);
4445 #endif
4446 display = 0;
4447 execvpe(*cmdv, cmdv, NewEnv + 3);
4448 Panic(errno, "%s", *cmdv);
4449 default:
4450 break;
4452 D_blankerpid = pid;
4453 evenq(&D_blankerev);
4454 D_blocked = 4;
4455 ClearAll();
4458 #endif
4460 struct layout *layouts;
4461 struct layout *laytab[MAXLAY];
4462 struct layout *layout_last, layout_last_marker;
4463 struct layout *layout_attach = &layout_last_marker;
4465 void
4466 FreeLayoutCv(cv)
4467 struct canvas *cv;
4469 struct canvas *cnext, *c = cv;
4470 for (; cv; cv = cnext)
4472 if (cv->c_slperp)
4474 FreeLayoutCv(cv->c_slperp);
4475 free(cv->c_slperp);
4476 cv->c_slperp = 0;
4478 cnext = cv->c_slnext;
4479 cv->c_slnext = 0;
4480 if (cv != c)
4481 free(cv);
4485 static void
4486 DupLayoutCv(cvf, cvt, save)
4487 struct canvas *cvf, *cvt;
4488 int save;
4490 while(cvf)
4492 cvt->c_slorient = cvf->c_slorient;
4493 cvt->c_slweight = cvf->c_slweight;
4494 if (cvf == D_forecv)
4495 D_forecv = cvt;
4496 if (!save)
4498 cvt->c_display = display;
4499 if (!cvf->c_slperp)
4501 cvt->c_captev.type = EV_TIMEOUT;
4502 cvt->c_captev.data = (char *)cvt;
4503 cvt->c_captev.handler = cv_winid_fn;
4504 cvt->c_blank.l_cvlist = 0;
4505 cvt->c_blank.l_layfn = &BlankLf;
4506 cvt->c_blank.l_bottom = &cvt->c_blank;
4508 cvt->c_layer = cvf->c_layer;
4510 else
4512 struct win *p = cvf->c_layer ? Layer2Window(cvf->c_layer) : 0;
4513 cvt->c_layer = p ? &p->w_layer : 0;
4515 if (cvf->c_slperp)
4517 cvt->c_slperp = (struct canvas *)calloc(1, sizeof(struct canvas));
4518 cvt->c_slperp->c_slback = cvt;
4519 CanvasInitBlank(cvt->c_slperp);
4520 DupLayoutCv(cvf->c_slperp, cvt->c_slperp, save);
4522 if (cvf->c_slnext)
4524 cvt->c_slnext = (struct canvas *)calloc(1, sizeof(struct canvas));
4525 cvt->c_slnext->c_slprev = cvt;
4526 cvt->c_slnext->c_slback = cvt->c_slback;
4527 CanvasInitBlank(cvt->c_slnext);
4529 cvf = cvf->c_slnext;
4530 cvt = cvt->c_slnext;
4534 void
4535 PutWindowCv(cv)
4536 struct canvas *cv;
4538 struct win *p;
4539 for (; cv; cv = cv->c_slnext)
4541 if (cv->c_slperp)
4543 PutWindowCv(cv->c_slperp);
4544 continue;
4546 p = cv->c_layer ? (struct win *)cv->c_layer->l_data : 0;
4547 cv->c_layer = 0;
4548 SetCanvasWindow(cv, p);
4552 struct layout *
4553 CreateLayout(title, startat)
4554 char *title;
4555 int startat;
4557 struct layout *lay;
4558 int i;
4560 if (startat >= MAXLAY || startat < 0)
4561 startat = 0;
4562 for (i = startat; ;)
4564 if (!laytab[i])
4565 break;
4566 if (++i == MAXLAY)
4567 i = 0;
4568 if (i == startat)
4570 Msg(0, "No more layouts\n");
4571 return 0;
4574 lay = (struct layout *)calloc(1, sizeof(*lay));
4575 lay->lay_title = SaveStr(title);
4576 lay->lay_autosave = 1;
4577 lay->lay_number = i;
4578 laytab[i] = lay;
4579 lay->lay_next = layouts;
4580 layouts = lay;
4581 return lay;
4584 void
4585 SaveLayout(name, cv)
4586 char *name;
4587 struct canvas *cv;
4589 struct layout *lay;
4590 struct canvas *fcv;
4591 for (lay = layouts; lay; lay = lay->lay_next)
4592 if (!strcmp(lay->lay_title, name))
4593 break;
4594 if (lay)
4595 FreeLayoutCv(&lay->lay_canvas);
4596 else
4597 lay = CreateLayout(name, 0);
4598 if (!lay)
4599 return;
4600 fcv = D_forecv;
4601 DupLayoutCv(cv, &lay->lay_canvas, 1);
4602 lay->lay_forecv = D_forecv;
4603 D_forecv = fcv;
4604 D_layout = lay;
4607 void
4608 AutosaveLayout(lay)
4609 struct layout *lay;
4611 struct canvas *fcv;
4612 if (!lay || !lay->lay_autosave)
4613 return;
4614 FreeLayoutCv(&lay->lay_canvas);
4615 fcv = D_forecv;
4616 DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
4617 lay->lay_forecv = D_forecv;
4618 D_forecv = fcv;
4621 struct layout *
4622 FindLayout(name)
4623 char *name;
4625 struct layout *lay;
4626 char *s;
4627 int i;
4628 for (i = 0, s = name; *s >= '0' && *s <= '9'; s++)
4629 i = i * 10 + (*s - '0');
4630 if (!*s && s != name && i >= 0 && i < MAXLAY)
4631 return laytab[i];
4632 for (lay = layouts; lay; lay = lay->lay_next)
4633 if (!strcmp(lay->lay_title, name))
4634 break;
4635 return lay;
4638 void
4639 LoadLayout(lay, cv)
4640 struct layout *lay;
4641 struct canvas *cv;
4643 AutosaveLayout(D_layout);
4644 if (!lay)
4646 while (D_canvas.c_slperp)
4647 FreeCanvas(D_canvas.c_slperp);
4648 MakeDefaultCanvas();
4649 SetCanvasWindow(D_forecv, 0);
4650 D_layout = 0;
4651 return;
4653 while (D_canvas.c_slperp)
4654 FreeCanvas(D_canvas.c_slperp);
4655 D_cvlist = 0;
4656 D_forecv = lay->lay_forecv;
4657 DupLayoutCv(&lay->lay_canvas, &D_canvas, 0);
4658 D_canvas.c_ye = D_height - 1 - ((D_canvas.c_slperp && D_canvas.c_slperp->c_slnext) || captionalways) - (D_has_hstatus == HSTATUS_LASTLINE);
4659 ResizeCanvas(&D_canvas);
4660 RecreateCanvasChain();
4661 RethinkDisplayViewports();
4662 PutWindowCv(&D_canvas);
4663 ResizeLayersToCanvases();
4664 D_layout = lay;
4667 void
4668 NewLayout(title, startat)
4669 char *title;
4670 int startat;
4672 struct layout *lay;
4673 struct canvas *fcv;
4675 lay = CreateLayout(title, startat);
4676 if (!lay)
4677 return;
4678 LoadLayout(0, &D_canvas);
4679 fcv = D_forecv;
4680 DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
4681 lay->lay_forecv = D_forecv;
4682 D_forecv = fcv;
4683 D_layout = lay;
4684 lay->lay_autosave = 1;
4687 static char *
4688 AddLayoutsInfo(buf, len, where)
4689 char *buf;
4690 int len;
4691 int where;
4693 char *s, *ss, *t;
4694 struct layout *p, **pp;
4695 int l;
4697 s = ss = buf;
4698 for (pp = laytab; pp < laytab + MAXLAY; pp++)
4700 if (pp - laytab == where && ss == buf)
4701 ss = s;
4702 if ((p = *pp) == 0)
4703 continue;
4704 t = p->lay_title;
4705 l = strlen(t);
4706 if (l > 20)
4707 l = 20;
4708 if (s - buf + l > len - 24)
4709 break;
4710 if (s > buf)
4712 *s++ = ' ';
4713 *s++ = ' ';
4715 sprintf(s, "%d", p->lay_number);
4716 if (p->lay_number == where)
4717 ss = s;
4718 s += strlen(s);
4719 if (display && p == D_layout)
4720 *s++ = '*';
4721 *s++ = ' ';
4722 strncpy(s, t, l);
4723 s += l;
4725 *s = 0;
4726 return ss;
4729 void
4730 ShowLayouts(where)
4731 int where;
4733 char buf[1024];
4734 char *s, *ss;
4736 if (!display)
4737 return;
4738 if (!layouts)
4740 Msg(0, "No layouts defined\n");
4741 return;
4743 if (where == -1 && D_layout)
4744 where = D_layout->lay_number;
4745 ss = AddLayoutsInfo(buf, sizeof(buf), where);
4746 s = buf + strlen(buf);
4747 if (ss - buf > D_width / 2)
4749 ss -= D_width / 2;
4750 if (s - ss < D_width)
4752 ss = s - D_width;
4753 if (ss < buf)
4754 ss = buf;
4757 else
4758 ss = buf;
4759 Msg(0, "%s", ss);
4762 void
4763 RemoveLayout(lay)
4764 struct layout *lay;
4766 struct layout **layp = &layouts;
4768 for (; *layp; layp = &(*layp)->lay_next)
4770 if (*layp == lay)
4772 *layp = lay->lay_next;
4773 break;
4776 laytab[lay->lay_number] = (struct layout *)0;
4778 if (display && D_layout == lay)
4779 D_layout = (struct layout *)0;
4781 FreeLayoutCv(&lay->lay_canvas);
4783 if (lay->lay_title)
4784 free(lay->lay_title);
4785 free(lay);
4787 if (layouts)
4788 LoadLayout((display && D_layout) ? D_layout : *layp ? *layp : layouts,
4789 display ? &D_canvas : (struct canvas *)0);
4790 Activate(0);