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)
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>
33 # include <sys/ioctl.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 *));
49 static void disp_writeev_eagain
__P((struct event
*, char *));
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 *));
56 static void disp_map_fn
__P((struct event
*, char *));
58 static void disp_idle_fn
__P((struct event
*, char *));
60 static void disp_blanker_fn
__P((struct event
*, char *));
62 static void WriteLP
__P((int, int));
63 static void INSERTCHAR
__P((int));
64 static void RAW_PUTCHAR
__P((int));
66 static void SetBackColor
__P((int));
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
;
94 extern int pty_preopen
;
95 #if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
96 extern struct winsize glwz
;
99 extern int real_uid
, real_gid
;
103 * tputs needs this to calculate the padding
107 #endif /* NEED_OSPEED */
111 struct display
*display
, *displays
;
113 int attr2color
[8][4];
118 struct display TheDisplay
;
124 int defobuflimit
= OBUF_MAX
;
125 int defnonblock
= -1;
126 int defmousetrack
= 0;
131 int hardstatusemu
= HSTATUS_IGNORE
;
133 int focusminwidth
, focusminheight
;
136 * Default layer management
140 DefProcess(bufp
, lenp
)
149 DefRedisplayLine(y
, xs
, xe
, isblank
)
150 int y
, xs
, xe
, isblank
;
152 if (isblank
== 0 && y
>= 0)
153 DefClearLine(y
, xs
, xe
, 0);
157 DefClearLine(y
, xs
, xe
, bce
)
160 LClearLine(flayer
, y
, xs
, xe
, bce
, (struct mline
*)0);
165 DefRewrite(y
, xs
, xe
, rend
, doit
)
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
=
213 flayer
->l_width
= wi
;
214 flayer
->l_height
= he
;
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.
226 MakeDisplay(uname
, utty
, term
, fd
, pid
, Mode
)
227 char *uname
, *utty
, *term
;
232 struct baud_values
*b
;
234 if (!*(u
= FindUserPtr(uname
)) && UserAdd(uname
, (char *)0, u
))
235 return 0; /* could not find or add user */
238 if ((display
= (struct display
*)calloc(1, sizeof(*display
))) == 0)
243 bzero((char *)&TheDisplay
, sizeof(TheDisplay
));
244 display
= &TheDisplay
;
246 display
->d_next
= displays
;
249 D_nonblock
= defnonblock
;
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
;
258 D_writeev
.condpos
= &D_obuflen
;
259 D_writeev
.condneg
= &D_obuffree
;
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
;
274 D_mapev
.type
= EV_TIMEOUT
;
275 D_mapev
.data
= (char *)display
;
276 D_mapev
.handler
= disp_map_fn
;
278 D_idleev
.type
= EV_TIMEOUT
;
279 D_idleev
.data
= (char *)display
;
280 D_idleev
.handler
= disp_idle_fn
;
282 D_blankerev
.type
= EV_READ
;
283 D_blankerev
.data
= (char *)display
;
284 D_blankerev
.handler
= disp_blanker_fn
;
288 D_status_obuffree
= -1;
289 Resize_obuf(); /* Allocate memory for buffer */
290 D_obufmax
= defobuflimit
;
291 D_obuflenmax
= D_obuflen
- D_obufmax
;
293 D_auto_nuke
= defautonuke
;
300 if ((b
= lookup_baud((int)cfgetospeed(&D_OldMode
.tio
))))
304 if ((b
= lookup_baud(D_OldMode
.tio
.c_cflag
& CBAUD
)))
307 D_dospeed
= (short)D_OldMode
.m_ttyb
.sg_ospeed
;
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;
317 D_processinput
= ProcessInput
;
318 D_mousetrack
= defmousetrack
;
328 struct display
*d
, **dp
;
342 SetTTY(D_userfd
, &D_OldMode
);
343 fcntl(D_userfd
, F_SETFL
, 0);
349 if (D_processinputdata
)
350 free(D_processinputdata
);
351 D_processinputdata
= 0;
376 if (bd
.bd_dpy
== display
)
378 bd
.bd_start_braille
= 0;
384 for (dp
= &displays
; (d
= *dp
) ; dp
= &d
->d_next
)
388 if (D_status_lastmsg
)
389 free(D_status_lastmsg
);
392 *dp
= display
->d_next
;
394 ASSERT(display
== displays
);
395 ASSERT(display
== &TheDisplay
);
399 while (D_canvas
.c_slperp
)
400 FreeCanvas(D_canvas
.c_slperp
);
403 for (p
= windows
; p
; p
= p
->w_next
)
405 if (p
->w_pdisplay
== display
)
407 if (p
->w_lastdisp
== display
)
409 if (p
->w_readev
.condneg
== &D_status
|| p
->w_readev
.condneg
== &D_obuflenmax
)
410 p
->w_readev
.condpos
= p
->w_readev
.condneg
= 0;
413 for (p
= windows
; p
; p
= p
->w_next
)
414 if (p
->w_zdisplay
== display
)
423 free((char *)display
);
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
;
450 if ((cv
= (struct canvas
*)calloc(1, sizeof *cv
)) == 0)
453 cv
->c_xe
= D_width
- 1;
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
);
460 cv
->c_display
= display
;
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
;
481 RethinkDisplayViewports();
482 D_forecv
= cv
; /* default input focus */
486 static struct canvas
**
487 CreateCanvasChainRec(cv
, cvp
)
491 for (; cv
; cv
= cv
->c_slnext
)
494 cvp
= CreateCanvasChainRec(cv
->c_slperp
, cvp
);
505 RecreateCanvasChain()
508 cvp
= CreateCanvasChainRec(D_canvas
.c_slperp
, &D_cvlist
);
516 struct viewport
*vp
, *nvp
;
521 cv
->c_slprev
->c_slnext
= 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
;
529 FreeCanvas(cv
->c_slperp
);
538 /* remove from canvas chain as SetCanvasWindow might call
539 * some layer function */
540 for (cvp
= &D_cvlist
; *cvp
; cvp
= &(*cvp
)->c_next
)
547 p
= cv
->c_layer
? Layer2Window(cv
->c_layer
) : 0;
548 SetCanvasWindow(cv
, 0);
550 WindowChanged(p
, 'u');
551 if (flayer
== cv
->c_layer
)
553 for (vp
= cv
->c_vplist
; vp
; vp
= nvp
)
560 evdeq(&cv
->c_captev
);
569 for (; cv
; cv
= cv
->c_slnext
)
575 for (cvp
= cv
->c_slperp
; cvp
; cvp
= cvp
->c_slnext
)
578 n
= CountCanvas(cvp
->c_slperp
);
596 for (cvp
= cv
->c_slperp
; cvp
; cvp
= cvp
->c_slnext
)
599 n
= CountCanvas(cvp
->c_slperp
);
607 EqualizeCanvas(cv
, gflag
)
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
)
619 EqualizeCanvas(cv2
->c_slperp
, gflag
);
630 struct canvas
*cv2
, *cvn
, *fcv
;
631 int nh
, i
, maxi
, hh
, m
, w
, wsum
;
641 debug2("ResizeCanvas: %d,%d", xs
, ys
);
642 debug2(" %d,%d\n", xe
, ye
);
645 if (cv
->c_slorient
== SLICE_UNKN
)
647 ASSERT(!cv
->c_slnext
&& !cv
->c_slperp
);
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;
660 if (focusminwidth
|| focusminheight
)
662 debug("searching for focus canvas\n");
664 while (cv2
->c_slback
)
666 if (cv2
->c_slback
== cv
->c_slback
)
669 focusmin
= cv
->c_slorient
== SLICE_VERT
? focusminheight
: focusminwidth
;
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
);
681 m
= CountCanvas(cv
) * 2;
682 nh
= cv
->c_slorient
== SLICE_VERT
? ye
- ys
+ 2 : xe
- xs
+ 2;
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
);
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;
709 hh
= cv2
->c_slweight
? nh
* cv2
->c_slweight
/ w
: 0;
710 w
-= cv2
->c_slweight
;
712 debug2(" should %d min %d\n", hh
, m
);
718 debug2("need: %d, got %d\n", 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
;
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
;
737 cv
->c_slback
->c_ye
++;
738 cv
->c_slprev
->c_ye
++;
741 SetCanvasWindow(cv
, 0);
745 m
= cv
->c_slperp
? CountCanvasPerp(cv
) * 2 - 1 : 1;
748 hh
= cv
->c_slweight
? nh
* cv
->c_slweight
/ w
: 0;
751 debug2(" should %d min %d\n", hh
, m
);
755 debug1(" -> %d\n", hh
);
759 int hx
= need
* (hh
- m
- 1) / got
;
760 debug3(" -> %d - %d = %d\n", hh
, hx
, hh
- hx
);
764 debug2(" now need=%d got=%d\n", need
, got
);
767 /* hh is window size plus pation line */
768 if (i
+ hh
> maxi
+ 2)
771 debug1(" not enough space, reducing to %d\n", hh
);
773 if (i
+ hh
== maxi
+ 1)
776 debug(" incrementing as no other canvas will fit\n");
778 if (cv
->c_slorient
== SLICE_VERT
)
783 cv
->c_ye
= i
+ hh
- 2;
790 cv
->c_xe
= i
+ hh
- 2;
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;
803 if (!cv
->c_slperp
->c_slnext
)
805 debug("deleting perp node\n");
806 FreePerp(cv
->c_slperp
);
814 static struct canvas
*
819 debug("Creating new perp node\n");
821 if ((pcv
= (struct canvas
*)calloc(1, sizeof *cv
)) == 0)
824 pcv
->c_display
= cv
->c_display
;
825 pcv
->c_slnext
= cv
->c_slnext
;
826 pcv
->c_slprev
= cv
->c_slprev
;
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
;
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
;
839 pcv
->c_slnext
->c_slprev
= pcv
;
841 pcv
->c_slprev
->c_slnext
= pcv
;
842 pcv
->c_slweight
= cv
->c_slweight
;
843 CanvasInitBlank(pcv
);
849 cv
->c_slorient
= SLICE_UNKN
;
862 cv
->c_slprev
= pcv
->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
;
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
;
879 cv
->c_slnext
->c_slprev
= cv
;
892 debug2("AddCanvas orient %d, forecv is %d\n", orient
, cv
->c_slorient
);
894 if (cv
->c_slorient
!= SLICE_UNKN
&& cv
->c_slorient
!= orient
)
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
)
917 return -1; /* can't fit in */
919 if ((cv
= (struct canvas
*)calloc(1, sizeof *cv
)) == 0)
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
;
928 cv
->c_slnext
->c_slprev
= cv
;
929 cv
->c_slorient
= orient
;
930 cv
->c_slback
= D_forecv
->c_slback
;
938 cv
->c_display
= display
;
940 cv
->c_captev
.type
= EV_TIMEOUT
;
941 cv
->c_captev
.data
= (char *)cv
;
942 cv
->c_captev
.handler
= cv_winid_fn
;
950 EqualizeCanvas(cv
->c_slperp
, 0);
952 RecreateCanvasChain();
953 RethinkDisplayViewports();
954 ResizeLayersToCanvases();
964 debug("RemCanvas\n");
966 if (cv
->c_slorient
== SLICE_UNKN
)
972 if (!cv
->c_slnext
->c_slnext
&& cv
->c_slback
->c_slback
)
974 /* two canvases in slice, kill perp node */
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
;
986 D_forecv
= cv
->c_slprev
;
988 D_forecv
= cv
->c_slnext
;
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
;
1000 cv
->c_slback
->c_ye
= ++ye
; /* caption line no longer needed */
1003 EqualizeCanvas(cv
->c_slperp
, 0);
1006 D_fore
= Layer2Window(D_forecv
->c_layer
);
1007 flayer
= D_forecv
->c_layer
;
1009 RecreateCanvasChain();
1010 RethinkDisplayViewports();
1011 ResizeLayersToCanvases();
1017 struct canvas
*cv
= D_forecv
, *ocv
= 0;
1022 cv
->c_slprev
->c_slnext
= cv
->c_slnext
;
1027 cv
->c_slnext
->c_slprev
= cv
->c_slprev
;
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
);
1037 D_canvas
.c_slperp
= cv
;
1038 cv
->c_slback
= &D_canvas
;
1041 ASSERT(!cv
->c_slperp
);
1043 D_canvas
.c_ye
++; /* caption line no longer needed */
1044 ResizeCanvas(&D_canvas
);
1045 RecreateCanvasChain();
1046 RethinkDisplayViewports();
1047 ResizeLayersToCanvases();
1051 RethinkDisplayViewports()
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
)
1063 bzero((char *)vp
, sizeof(*vp
));
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)
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
;
1086 if ((vp
= (struct viewport
*)malloc(sizeof *vp
)) == 0)
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
;
1098 if ((vp
= (struct viewport
*)malloc(sizeof *vp
)) == 0)
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
;
1110 if ((vp
= (struct viewport
*)malloc(sizeof *vp
)) == 0)
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
;
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
;
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
;
1142 RethinkViewportOffsets(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.
1167 /* Check for toggle */
1168 if (D_IM
&& strcmp(D_IM
, D_EI
))
1175 /* Check for toggle */
1176 if (D_KS
&& strcmp(D_KS
, D_KE
))
1178 if (D_CCS
&& strcmp(D_CCS
, D_CCE
))
1186 D_rend
= mchar_null
;
1189 ResizeDisplay(D_defwidth
, D_defheight
);
1190 ChangeScrollRegion(0, D_height
- 1);
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);
1209 ResizeDisplay(D_defwidth
, D_defheight
);
1211 ChangeScrollRegion(0, D_height
- 1);
1214 CursorVisibility(0);
1218 SetRendition(&mchar_null
);
1225 ShowHStatus((char *)0);
1230 GotoPos(0, D_height
- 1);
1244 if (!D_insert
&& D_x
< D_width
- 1)
1258 RefreshLine(D_y
, D_x
, D_width
-1, 0);
1270 if (D_insert
&& D_x
< D_width
- 1)
1279 if (D_x
< D_width
- 1)
1286 if (D_CLP
|| D_y
!= D_bot
)
1291 GotoPos(D_width
- 1, y
);
1294 debug("PUTCHARLP: lp_missing!\n");
1299 /* XXX -> PutChar ? */
1303 D_lpchar
.image
= D_mbcs
;
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.
1323 if (D_encoding
== UTF8
)
1325 c
= (c
& 255) | (unsigned char)D_rend
.font
<< 8;
1331 D_x
+= D_AM
? 1 : -1;
1334 else if (utf8_isdouble(c
))
1343 AddCStr2(D_CS0
, '0');
1353 if (is_dw_font(D_rend
.font
))
1363 if (D_x
== D_width
- 1)
1364 D_x
+= D_AM
? 1 : -1;
1369 # if defined(ENCODINGS) && defined(DW_CHARS)
1371 c
= PrepareEncodedChar(c
);
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
]);
1379 AddChar(D_rend
.font
!= '0' ? c
: D_c0_tab
[(int)(unsigned char)c
]);
1387 if (++D_x
>= D_width
)
1391 else if (!D_CLP
|| D_x
> D_width
)
1394 if (D_y
< D_height
-1 && D_y
!= D_bot
)
1412 /* this is for ESC-sequences only (AddChar is a macro) */
1421 if (display
&& s
&& *s
)
1424 tputs(s
, 1, DoAddChar
);
1433 if (display
&& s
&& *s
)
1436 tputs(tgoto(s
, 0, c
), 1, DoAddChar
);
1441 /* Insert mode is a toggle on some terminals, so we need this hack:
1447 if (display
&& on
!= D_insert
&& D_IM
)
1457 /* ...and maybe keypad application mode is a toggle, too:
1467 if (display
&& D_keypad
!= on
&& D_KS
)
1486 if (display
&& D_cursorkeys
!= on
&& D_CCS
)
1501 if (display
&& D_revvid
!= on
&& D_CVR
)
1515 if (display
&& D_curvis
!= v
)
1518 AddCStr(D_VE
); /* do this always, just to be safe */
1520 if (v
== -1 && D_VI
)
1522 else if (v
== 1 && D_VS
)
1537 if (mode
< D_mousetrack
)
1538 mode
= D_mousetrack
;
1540 if (D_mouse
!= mode
)
1547 sprintf(mousebuf
, "\033[?%dl", D_mouse
);
1552 sprintf(mousebuf
, "\033[?%dh", mode
);
1579 tputs(s
, 1, CountChars
);
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
;
1595 debug3("CallRewrite %d %d %d\n", y
, xs
, xe
);
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
)
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
)
1613 flayer
= cv
->c_layer
;
1614 cvlist
= flayer
->l_cvlist
;
1615 cvlnext
= cv
->c_lnext
;
1616 flayer
->l_cvlist
= cv
;
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
;
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 */
1633 if (D_encoding
== UTF8
)
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);
1642 cost
+= D_EIcost
+ D_IMcost
;
1651 register int dy
, dx
, x1
, y1
;
1652 register int costx
, costy
;
1656 enum move_t xm
= M_NONE
, ym
= M_NONE
;
1667 x1
= -1; /* don't know how the terminal treats this */
1675 if (dy
== 0 && dx
== 0)
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 ? */
1686 if (D_HO
&& !x2
&& !y2
)
1689 AddCStr(tgoto(D_CM
, x2
, y2
));
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
))
1701 /* Calculate CMcost */
1702 if (D_HO
&& !x2
&& !y2
)
1705 s
= tgoto(D_CM
, x2
, y2
);
1706 CMcost
= CalcCost(s
);
1708 /* Calculate the cost to move the cursor to the right x position */
1710 if (x1
>= 0) /* relativ x positioning only if we know where we are */
1714 if (D_CRI
&& (dx
> 1 || !D_ND
))
1716 costx
= CalcCost(tgoto(D_CRI
, 0, dx
));
1719 if ((m
= D_NDcost
* dx
) < costx
)
1724 /* Speedup: dx <= LayRewrite() */
1725 if (dx
< costx
&& (m
= CallRewrite(y1
, x1
, x2
- 1, 0)) < costx
)
1733 if (D_CLE
&& (dx
< -1 || !D_BC
))
1735 costx
= CalcCost(tgoto(D_CLE
, 0, -dx
));
1738 if ((m
= -dx
* D_LEcost
) < costx
)
1747 /* Speedup: LayRewrite() >= x2 */
1748 if (x2
+ D_CRcost
< costx
&& (m
= (x2
? CallRewrite(y1
, 0, x2
- 1, 0) : 0) + D_CRcost
) < costx
)
1754 /* Check if it is already cheaper to do CM */
1755 if (costx
>= CMcost
)
1758 /* Calculate the cost to move the cursor to the right y position */
1762 if (D_CDO
&& dy
> 1) /* DO & NL are always != 0 */
1764 costy
= CalcCost(tgoto(D_CDO
, 0, dy
));
1767 if ((m
= dy
* ((x2
== 0) ? D_NLcost
: D_DOcost
)) < costy
)
1775 if (D_CUP
&& (dy
< -1 || !D_UP
))
1777 costy
= CalcCost(tgoto(D_CUP
, 0, -dy
));
1780 if ((m
= -dy
* D_UPcost
) < costy
)
1789 /* Finally check if it is cheaper to do CM */
1790 if (costx
+ costy
>= CMcost
)
1800 AddCStr2(D_CLE
, -dx
);
1807 AddCStr2(D_CRI
, dx
);
1816 (void) CallRewrite(y1
, x1
, x2
- 1, 1);
1829 AddCStr2(D_CUP
, -dy
);
1832 s
= (x2
== 0) ? D_NL
: D_DO
;
1837 AddCStr2(D_CDO
, dy
);
1850 ClearArea(0, 0, 0, D_width
- 1, D_width
- 1, D_height
- 1, 0, 0);
1854 ClearArea(x1
, y1
, xs
, xe
, x2
, y2
, bce
, uselayfn
)
1855 int x1
, y1
, xs
, xe
, x2
, y2
, bce
, uselayfn
;
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
);
1874 if (D_UT
) /* Safe to erase ? */
1875 SetRendition(&mchar_null
);
1880 if (D_lp_missing
&& y1
<= D_bot
&& xe
>= D_width
- 1)
1882 if (y2
> D_bot
|| (y2
== D_bot
&& x2
>= D_width
- 1))
1885 if (x2
== D_width
- 1 && (xs
== 0 || y1
== y2
) && xe
== D_width
- 1 && y2
== D_height
- 1 && (!bce
|| D_BE
))
1888 if (x1
== 0 && y1
== 0 && D_auto_nuke
)
1891 if (x1
== 0 && y1
== 0 && D_CL
)
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
))
1908 if (x1
== 0 && xs
== 0 && (xe
== D_width
- 1 || y1
== y2
) && y1
== 0 && D_CCD
&& (!bce
|| D_BE
))
1915 for (y
= y1
; y
<= y2
; y
++, x1
= xs
)
1919 if (x1
== 0 && D_CB
&& (xxe
!= D_width
- 1 || (D_x
== xxe
&& D_y
== y
)) && (!bce
|| D_BE
))
1925 if (xxe
== D_width
- 1 && D_CE
&& (!bce
|| D_BE
))
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
)
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
)
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
;
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
;
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.
1977 /* XXX do em all? */
1979 ChangeScrollRegion(0, D_height
- 1);
1982 CursorVisibility(0);
1984 SetRendition(&mchar_null
);
1991 if (cur_only
> 0 && D_fore
)
1992 RefreshArea(0, D_fore
->w_y
, D_width
- 1, D_fore
->w_y
, 1);
1996 CV_CALL(D_forecv
, LayRestore();LaySetCursor());
2000 RedisplayDisplays(cur_only
)
2003 struct display
*olddisplay
= display
;
2004 for (display
= displays
; display
; display
= display
->d_next
)
2005 Redisplay(cur_only
);
2006 display
= olddisplay
;
2012 ScrollH(y
, xs
, xe
, n
, bce
, oml
)
2013 int y
, xs
, xe
, n
, bce
;
2020 if (xe
!= D_width
- 1)
2022 RefreshLine(y
, xs
, xe
, 0);
2023 /* UpdateLine(oml, y, xs, xe); */
2028 SetRendition(&mchar_null
);
2035 if (n
>= xe
- xs
+ 1)
2037 if (D_CDC
&& !(n
== 1 && D_DC
))
2046 RefreshLine(y
, xs
, xe
, 0);
2047 /* UpdateLine(oml, y, xs, xe); */
2053 if (-n
>= xe
- xs
+ 1)
2057 if (D_CIC
&& !(n
== -1 && D_IC
))
2058 AddCStr2(D_CIC
, -n
);
2067 SetRendition(&mchar_null
);
2073 bce
= 0; /* all done */
2077 /* UpdateLine(oml, y, xs, xe); */
2078 RefreshLine(y
, xs
, xe
, 0);
2084 SetRendition(&mchar_null
);
2090 bce
= 0; /* all done */
2096 ClearLine((struct mline
*)0, y
, xe
- n
+ 1, xe
, bce
);
2098 ClearLine((struct mline
*)0, y
, xs
, xs
- n
- 1, bce
);
2100 if (D_lp_missing
&& y
== D_bot
)
2103 WriteLP(D_width
- 1 - n
, y
);
2109 ScrollV(xs
, ys
, xe
, ye
, n
, bce
)
2110 int xs
, ys
, xe
, ye
, n
, bce
;
2115 int alok
, dlok
, aldlfaster
;
2121 if (n
>= ye
- ys
+ 1 || -n
>= ye
- ys
+ 1)
2123 ClearArea(xs
, ys
, xs
, xe
, xe
, ye
, bce
, 0);
2126 if (xs
> D_vpxmin
|| xe
< D_vpxmax
)
2128 RefreshArea(xs
, ys
, xe
, ye
, 0);
2134 if (D_bot
> ye
|| D_bot
< ys
)
2139 if (missy
> ye
|| missy
< ys
)
2150 if (n
>= ye
- ys
+ 1)
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
);
2164 (oldbot
== D_bot
&& up
&& D_top
== ys
&& D_bot
== ye
)))
2166 WriteLP(D_width
- 1, oldbot
);
2167 if (oldbot
== D_bot
) /* have scrolled */
2172 ChangeScrollRegion(oldtop, oldbot);
2175 ClearLine((struct mline
*)0, ye
, xs
, xe
, bce
);
2182 SetRendition(&mchar_null
);
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
)
2195 for(i
= n
; i
-- > 0; )
2196 AddCStr(D_NL
); /* was SF, I think NL is faster */
2201 for(i
= n
; i
-- > 0; )
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
))
2216 if (!up
|| ye
!= D_bot
)
2218 GotoPos(0, up
? ye
+1-n
: ys
);
2219 if (D_CAL
&& !(n
== 1 && D_AL
))
2228 RefreshArea(xs
, ys
, xe
, ye
, 0);
2234 ClearArea(xs
, ye
- n
+ 1, xs
, xe
, xe
, ye
, bce
, 0);
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
);
2241 ChangeScrollRegion(oldtop, oldbot);
2242 if (D_lp_missing && missy != D_bot)
2243 WriteLP(D_width - 1, missy);
2251 register int i
, j
, old
, typ
;
2253 if (!display
|| (old
= D_rend
.attr
) == new)
2256 D_col16change
= (old
^ new) & (A_BFG
| A_BBG
);
2257 new ^= D_col16change
;
2261 #if defined(TERMINFO) && defined(USE_SGR)
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 ,
2274 rend_setdefault(&D_rend
);
2281 if ((new & old
) != old
)
2291 /* ansi attrib handling: \E[m resets color, too */
2293 rend_setdefault(&D_rend
);
2298 /* D_ME may also reset the alternate charset */
2310 for (i
= 0, j
= 1; old
&& i
< NATTR
; i
++, j
<<= 1)
2317 AddCStr(D_attrtab
[i
]);
2318 typ
|= D_attrtyp
[i
];
2329 int old
= D_rend
.font
;
2330 if (!display
|| old
== new)
2334 if (D_encoding
&& CanEncodeFont(D_encoding
, new))
2336 if (new == D_realfont
)
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]);
2347 if (!D_CG0
&& new != '0')
2366 AddCStr2(D_CS0
, new);
2381 jj
= (jj
- 232) / 6;
2382 jj
= (jj
& 1) << 3 | (jj
& 2 ? 7 : 0);
2390 min
= r
< g
? (r
< b
? r
: b
) : (g
< b
? g
: b
);
2391 max
= r
> g
? (r
> b
? r
: b
) : (g
> b
? g
: b
);
2393 jj
= ((max
+ 1) & 2) << 2 | ((max
+ 1) & 4 ? 7 : 0);
2395 jj
= (b
- min
) / (max
- min
) << 2 | (g
- min
) / (max
- min
) << 1 | (r
-
2396 min
) / (max
- min
) | (max
> 3 ? 8 : 0);
2409 return (jj
- 232) / 3 + 80;
2416 return ((r
+ 1) / 2) * 16 + ((g
+ 1) / 2) * 4 + ((b
+ 1) / 2) + 16;
2427 static unsigned char sftrans
[8] = {0,4,2,6,1,5,3,7};
2432 of
= rend_getfg(&D_rend
);
2433 ob
= rend_getbg(&D_rend
);
2436 /* intense default not invented yet */
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
)))
2454 oattr
= D_rend
.attr
;
2455 AddCStr(D_ME
? D_ME
: "\033[m");
2459 /* D_ME may also reset the alternate charset */
2472 rend_setfg(&D_rend
, f
);
2473 rend_setbg(&D_rend
, b
);
2479 f
= f
? coli2e(f
) : -1;
2480 b
= b
? coli2e(b
) : -1;
2481 of
= of
? coli2e(of
) : -1;
2482 ob
= ob
? coli2e(ob
) : -1;
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
)
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
)
2499 if (f
!= of
&& f
!= (of
| 8))
2502 AddCStr("\033[39m"); /* works because AX is set */
2504 AddCStr2(D_CAF
, f
& 7);
2506 AddCStr2(D_CSF
, sftrans
[f
& 7]);
2508 if (b
!= ob
&& b
!= (ob
| 8))
2511 AddCStr("\033[49m"); /* works because AX is set */
2513 AddCStr2(D_CAB
, b
& 7);
2515 AddCStr2(D_CSB
, sftrans
[b
& 7]);
2518 if (f
!= of
&& D_CXT
&& (f
& 8) != 0 && f
!= -1)
2521 AddCStr2("\033[9%p1%dm", f
& 7);
2523 AddCStr2("\033[9%dm", f
& 7);
2526 if (b
!= ob
&& D_CXT
&& (b
& 8) != 0 && b
!= -1)
2529 AddCStr2("\033[10%p1%dm", b
& 7);
2531 AddCStr2("\033[10%dm", b
& 7);
2543 SetColor(rend_getfg(&D_rend
), new);
2554 if (nattr2color
&& D_hascolor
&& (mc
->attr
& nattr2color
) != 0)
2556 static struct mchar mmc
;
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
);
2569 ApplyAttrColor(attr2color
[i
][0], &mmc
);
2572 debug2("SetRendition: mapped to %02x %02x\n", (unsigned char)mc
->attr
, 0x99 - (unsigned char)mc
->color
);
2575 if (D_hascolor
&& D_CC8
&& (mc
->attr
& (A_BFG
|A_BBG
)))
2578 if ((mc
->attr
& A_BFG
) && D_MD
)
2580 if ((mc
->attr
& A_BBG
) && D_MB
)
2582 if (D_rend
.attr
!= a
)
2586 # endif /* COLORS16 */
2588 if (D_rend
.attr
!= mc
->attr
)
2592 if (D_rend
.color
!= mc
->color
2594 || D_rend
.colorx
!= mc
->colorx
2600 SetColor(rend_getfg(mc
), rend_getbg(mc
));
2603 if (D_rend
.font
!= mc
->font
)
2609 SetRenditionMline(ml
, x
)
2616 if (nattr2color
&& D_hascolor
&& (ml
->attr
[x
] & nattr2color
) != 0)
2619 copy_mline2mchar(&mc
, ml
, x
);
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
)
2629 if ((ml
->attr
[x
] & A_BBG
) && D_MB
)
2631 if (D_rend
.attr
!= a
)
2635 # endif /* COLORS16 */
2637 if (D_rend
.attr
!= ml
->attr
[x
])
2638 SetAttr(ml
->attr
[x
]);
2640 if (D_rend
.color
!= ml
->color
[x
]
2642 || D_rend
.colorx
!= ml
->colorx
[x
]
2650 copy_mline2mchar(&mc
, ml
, x
);
2651 SetColor(rend_getfg(&mc
), rend_getbg(&mc
));
2655 if (D_rend
.font
!= ml
->font
[x
])
2656 SetFont(ml
->font
[x
]);
2664 register char *s
, *t
;
2674 debug("tc not inited, just writing msg\n");
2675 if (D_processinputdata
)
2676 return; /* XXX: better */
2682 if (!use_hardstatus
|| !D_HS
)
2689 max
= D_WS
> 0 ? D_WS
: (D_width
- !D_CLP
);
2693 if (strcmp(msg
, D_status_lastmsg
) == 0)
2695 debug("same message - increase timeout");
2696 if (!D_status_obufpos
)
2697 SetTimeout(&D_statusev
, MsgWait
);
2700 RemoveStatusMinWait();
2702 for (s
= t
= msg
; *s
&& t
- msg
< max
; ++s
)
2705 else if ((unsigned char)*s
>= ' ' && *s
!= 0177)
2710 if (t
- msg
>= D_status_buflen
)
2713 if (D_status_lastmsg
)
2714 buf
= realloc(D_status_lastmsg
, t
- msg
+ 1);
2716 buf
= malloc(t
- msg
+ 1);
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
);
2736 if (D_status_len
< max
)
2738 /* Wayne Davison: add extra space for readability */
2740 SetRendition(&mchar_null
);
2742 if (D_status_len
< max
)
2754 D_status
= STATUS_ON_HS
;
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() */
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;
2774 display
= olddisplay
;
2776 D_status
= STATUS_ON_WIN
;
2783 struct display
*olddisplay
;
2784 struct layer
*oldflayer
;
2789 if (!(where
= D_status
))
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;
2800 D_status_obufpos
= 0;
2803 olddisplay
= display
;
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
);
2816 flayer
= D_forecv
? D_forecv
->c_layer
: 0;
2819 display
= olddisplay
;
2823 /* Remove the status but make sure that it is seen for MsgMinWait ms */
2825 RemoveStatusMinWait()
2827 /* XXX: should flush output first if D_status_obufpos is set */
2828 if (!D_status_bell
&& !D_status_obufpos
)
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);
2840 /* refresh the display's hstatus line */
2847 if (D_status
== STATUS_ON_WIN
&& D_has_hstatus
== HSTATUS_LASTLINE
&& STATLINE
== D_height
-1)
2848 return; /* sorry, in use */
2852 if (D_HS
&& D_has_hstatus
== HSTATUS_HS
)
2854 if (!D_hstatus
&& (str
== 0 || *str
== 0))
2856 debug("ShowHStatus: using HS\n");
2857 SetRendition(&mchar_null
);
2862 if (str
== 0 || *str
== 0)
2865 max
= D_WS
> 0 ? D_WS
: (D_width
- !D_CLP
);
2866 if ((int)strlen(str
) > max
)
2873 else if (D_has_hstatus
== HSTATUS_LASTLINE
)
2875 debug("ShowHStatus: using last line\n");
2878 str
= str
? str
: "";
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
)
2889 ClearArea(l
, D_height
- 1, l
, D_width
- 1, D_width
- 1, D_height
- 1, 0, 0);
2890 if (ox
!= -1 && oy
!= -1)
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");
2904 * Refreshes the harstatus of the fore window. Shouldn't be here...
2911 evdeq(&D_hstatusev
);
2912 if (D_status
== STATUS_ON_HS
)
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);
2918 if (D_has_hstatus
!= HSTATUS_IGNORE
&& D_hstatusev
.timeout
.tv_sec
)
2919 evenq(&D_hstatusev
);
2922 ShowHStatus((char *)0);
2925 /*********************************************************************/
2927 * Here come the routines that refresh an arbitrary part of the screen.
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
);
2947 RefreshArea(xs
, ys
, xe
, ye
, isblank
)
2948 int xs
, ys
, xe
, ye
, isblank
;
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);
2959 for (y
= ys
; y
<= ye
; y
++)
2960 RefreshLine(y
, xs
, xe
, isblank
);
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
;
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. */
2998 if (y
== D_height
- 1 && D_has_hstatus
== HSTATUS_LASTLINE
)
3005 if (isblank
== 0 && D_CE
&& to
== D_width
- 1 && from
< to
)
3009 SetRendition(&mchar_null
);
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
;
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
++)
3037 if (from
== cv
->c_xe
+ 1 && y
>= cv
->c_ys
&& y
<= cv
->c_ye
+ 1)
3040 SetRendition(&mchar_so
);
3045 if (y
< cv
->c_ys
|| y
> cv
->c_ye
|| to
< cv
->c_xs
|| from
> cv
->c_xe
)
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
))
3062 continue; /* we advanced from */
3065 if (from
< lvp
->v_xs
)
3068 DisplayLine(&mline_null
, &mline_blank
, y
, from
, lvp
->v_xs
- 1);
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
)
3079 SetRendition(&mchar_blank
);
3080 while (from
<= lvp
->v_xe
&& from
- lvp
->v_xoff
< lcv
->c_layer
->l_width
)
3085 if (from
>= lvp
->v_xe
+ 1)
3088 if (lcv
->c_layer
== 0 || yy
>= lcv
->c_layer
->l_height
|| from
- lvp
->v_xoff
>= lcv
->c_layer
->l_width
)
3091 DisplayLine(&mline_null
, &mline_blank
, y
, from
, lvp
->v_xe
);
3092 from
= lvp
->v_xe
+ 1;
3096 if (xx
- lvp
->v_xoff
>= lcv
->c_layer
->l_width
)
3097 xx
= lcv
->c_layer
->l_width
+ lvp
->v_xoff
- 1;
3099 flayer
= lcv
->c_layer
;
3100 cvlist
= flayer
->l_cvlist
;
3101 cvlnext
= lcv
->c_lnext
;
3102 flayer
->l_cvlist
= lcv
;
3104 LayRedisplayLine(yy
, from
- lvp
->v_xoff
, xx
- lvp
->v_xoff
, isblank
);
3105 flayer
->l_cvlist
= cvlist
;
3106 lcv
->c_lnext
= cvlnext
;
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.
3124 struct mchar oldrend
;
3127 ASSERT(D_lp_missing
);
3129 debug2("WriteLP(%d,%d)\n", x2
, y2
);
3136 D_lpchar
= mchar_blank
;
3139 /* Can't use PutChar */
3141 SetRendition(&D_lpchar
);
3142 PUTCHAR(D_lpchar
.image
);
3145 PUTCHAR(D_lpchar
.mbcs
);
3148 SetRendition(&oldrend
);
3152 ClearLine(oml
, y
, from
, to
, bce
)
3154 int from
, to
, y
, bce
;
3158 struct mchar bcechar
;
3161 debug3("ClearLine %d,%d-%d\n", y
, from
, to
);
3162 if (D_UT
) /* Safe to erase ? */
3163 SetRendition(&mchar_null
);
3168 if (from
== 0 && D_CB
&& (to
!= D_width
- 1 || (D_x
== to
&& D_y
== y
)) && (!bce
|| D_BE
))
3174 if (to
== D_width
- 1 && D_CE
&& (!bce
|| D_BE
))
3185 DisplayLine(oml
, &mline_blank
, y
, from
, to
);
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
);
3194 DisplayLine(oml
, &mline_blank
, y
, from
, to
);
3199 DisplayLine(oml
, ml
, y
, from
, to
)
3200 struct mline
*oml
, *ml
;
3204 int last2flag
= 0, delete_lp
= 0;
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
))
3215 if ((D_IC
|| D_IM
) && from
< to
&& !dw_left(ml
, to
, D_encoding
))
3217 if ((D_IC
|| D_IM
) && from
< to
)
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
);
3236 /* finish dw-char (can happen after a wrap) */
3237 debug("DisplayLine finishing kanji\n");
3238 SetRenditionMline(ml
, from
);
3239 PUTCHAR(ml
->image
[from
]);
3243 for (x
= from
; x
<= to
; x
++)
3245 #if 0 /* no longer needed */
3246 if (x
|| D_x
!= D_width
|| D_y
!= y
- 1)
3249 if (x
< to
|| x
!= D_width
- 1 || ml
->image
[x
+ 1])
3250 if (cmp_mline(oml
, ml
, x
))
3255 if (dw_right(ml
, x
, D_encoding
))
3258 debug1("DisplayLine on right side of dw char- x now %d\n", x
);
3261 if (x
== to
&& dw_left(ml
, x
, D_encoding
))
3262 break; /* don't start new kanji */
3264 SetRenditionMline(ml
, x
);
3265 PUTCHAR(ml
->image
[x
]);
3267 if (dw_left(ml
, x
, D_encoding
))
3268 PUTCHAR(ml
->image
[++x
]);
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])
3279 SetRenditionMline(ml
, x
+ 1);
3280 PUTCHAR(ml
->image
[x
+ 1]);
3282 SetRenditionMline(ml
, x
);
3283 INSERTCHAR(ml
->image
[x
]);
3288 SetRendition(&mchar_null
);
3305 PUTCHARLP(c
->image
);
3310 if (D_encoding
== UTF8
)
3319 InsChar(c
, x
, xe
, y
, oml
)
3325 if (y
== D_bot
&& !D_CLP
)
3327 if (x
== D_width
- 1)
3333 if (xe
== D_width
- 1)
3339 PUTCHARLP(c
->image
);
3342 if (!(D_IC
|| D_CIC
|| D_IM
) || xe
!= D_width
- 1)
3344 RefreshLine(y
, x
, xe
, 0);
3346 /* UpdateLine(oml, y, x, xe); */
3353 if (c
->mbcs
&& D_IC
)
3358 AddCStr2(D_CIC
, c
->mbcs
? 2 : 1);
3367 RAW_PUTCHAR(c
->image
);
3372 if (D_encoding
== UTF8
)
3375 if (D_x
== D_width
- 1)
3378 RAW_PUTCHAR(c
->mbcs
);
3384 WrapChar(c
, x
, y
, xs
, ys
, xe
, ye
, ins
)
3393 bce
= rend_getbg(c
);
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
)
3405 ScrollV(xs
, ys
, xe
, ye
, 1, bce
);
3406 else if (y
< D_height
- 1)
3409 InsChar(c
, xs
, xe
, y
, 0);
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
);
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 */
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)
3442 if (ins
!= D_insert
)
3444 if (ins
&& !D_insert
)
3446 InsChar(c
, 0, xe
, y
, 0);
3447 debug2(" -> done with insert (%d,%d)\n", D_x
, D_y
);
3453 RAW_PUTCHAR(c
->image
);
3458 if (D_encoding
== UTF8
)
3461 RAW_PUTCHAR(c
->mbcs
);
3464 debug2(" -> done (%d,%d)\n", D_x
, D_y
);
3468 ResizeDisplay(wi
, he
)
3472 debug2("ResizeDisplay: to (%d,%d).\n", wi
, he
);
3473 if (D_width
== wi
&& D_height
== he
)
3475 debug("ResizeDisplay: No change\n");
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;
3487 debug("ResizeDisplay: using WS\n");
3488 AddCStr(tgoto(D_CWS
, wi
, he
));
3489 ChangeScreenSize(wi
, he
, 0);
3496 ChangeScrollRegion(newtop
, newbot
)
3501 if (newtop
== newbot
)
3502 return; /* xterm etc can't do it */
3506 newbot
= D_height
- 1;
3510 D_bot
= D_height
- 1;
3513 if (D_top
== newtop
&& D_bot
== newbot
)
3515 debug2("ChangeScrollRegion: (%d - %d)\n", newtop
, newbot
);
3516 AddCStr(tgoto(D_CS
, newbot
, newtop
));
3519 D_y
= D_x
= -1; /* Just in case... */
3528 static char oscs
[] = "0;\000\00020;\00039;\00049;\000";
3535 if (!D_xtermosc
[i
] && !*s
)
3538 s
= "screen"; /* always set icon name */
3540 s
= ""; /* no background */
3542 s
= "black"; /* black text */
3544 s
= "white"; /* on white background */
3547 AddStr(oscs
+ i
* 4);
3556 for (i
= 3; i
>= 0; i
--)
3562 * Output buffering routines
3574 if (D_encoding
== UTF8
)
3576 while ((c
= *str
++))
3577 AddUtf8((unsigned char)c
);
3581 while ((c
= *str
++))
3594 if (D_encoding
== UTF8
)
3596 while ((c
= *str
++) && n
-- > 0)
3597 AddUtf8((unsigned char)c
);
3601 while ((c
= *str
++) && n
-- > 0)
3616 l
= D_obufp
- D_obuf
;
3617 debug1("Flush(): %d\n", l
);
3620 ASSERT(l
+ D_obuffree
== D_obuflen
);
3630 if (fcntl(D_userfd
, F_SETFL
, 0))
3631 debug1("Warning: BLOCK fcntl failed: %d\n", errno
);
3639 FD_SET(D_userfd
, &w
);
3641 t
.tv_sec
= progress
;
3643 wr
= select(FD_SETSIZE
, (fd_set
*)0, &w
, (fd_set
*)0, &t
);
3648 debug1("Warning: select failed: %d\n", errno
);
3653 /* no progress after 3 seconds. sorry. */
3654 debug1("Warning: no progress after %d seconds\n", progress
);
3658 wr
= write(D_userfd
, p
, l
);
3663 debug1("Writing to display: %d\n", errno
);
3671 debug1("Warning: Flush could not write %d bytes\n", l
);
3676 if (fcntl(D_userfd
, F_SETFL
, FNBLOCK
))
3677 debug1("Warning: NBLOCK fcntl failed: %d\n", errno
);
3689 debug1("did freetty %d\n", D_userfd
);
3697 D_obuflenmax
= -D_obufmax
;
3703 * Asynchronous output routines by
3704 * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
3713 if (D_status_obuffree
>= 0)
3715 ASSERT(D_obuffree
== -1);
3716 RemoveStatusMinWait();
3717 if (--D_obuffree
> 0) /* redo AddChar decrement */
3720 if (D_obuflen
&& D_obuf
)
3722 ind
= D_obufp
- D_obuf
;
3724 D_obuffree
+= GRAIN
;
3725 D_obuf
= realloc(D_obuf
, D_obuflen
);
3732 D_obuf
= malloc(D_obuflen
);
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
);
3742 DisplaySleep1000(n
, eat
)
3754 debug("DisplaySleep has no display sigh\n");
3758 t
.tv_usec
= (n
% 1000) * 1000;
3759 t
.tv_sec
= n
/ 1000;
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");
3766 read(D_userfd
, &buf
, 1);
3768 debug2("DisplaySleep(%d) ending, eat was %d\n", n
, eat
);
3774 {/* Nuke pending output in current display, clear screen */
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
;
3783 len
= D_obufp
- D_obuf
;
3784 debug1("NukePending: nuking %d chars\n", len
);
3786 /* Throw away any output that we can... */
3788 tcflush(D_userfd
, TCOFLUSH
);
3791 (void) ioctl(D_userfd
, TCFLSH
, (char *) 1);
3800 /* Turn off all attributes. (Tim MacKenzie) */
3807 AddStr("\033[m"); /* why is D_ME not set? */
3812 /* Check for toggle */
3813 if (D_IM
&& strcmp(D_IM
, D_EI
))
3816 /* Check for toggle */
3818 if (D_KS
&& strcmp(D_KS
, D_KE
))
3820 if (D_CCS
&& strcmp(D_CCS
, D_CCE
))
3823 if (D_KS
&& strcmp(D_KS
, D_KE
))
3826 if (D_CCS
&& strcmp(D_CCS
, D_CCE
))
3831 D_rend
= mchar_null
;
3837 ChangeScrollRegion(oldtop
, oldbot
);
3838 SetRendition(&oldrend
);
3839 KeypadMode(oldkeypad
);
3840 CursorkeysMode(oldcursorkeys
);
3841 CursorVisibility(oldcurvis
);
3842 MouseMode(oldmouse
);
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 */
3857 /* linux' select can't handle flow control, so wait 100ms if
3861 disp_writeev_eagain(ev
, data
)
3865 display
= (struct display
*)data
;
3867 D_writeev
.type
= EV_WRITE
;
3868 D_writeev
.handler
= disp_writeev_fn
;
3874 disp_writeev_fn(ev
, data
)
3878 int len
, size
= OUTPUT_BLOCK_SIZE
;
3880 display
= (struct display
*)data
;
3881 len
= D_obufp
- D_obuf
;
3884 if (D_status_obufpos
&& size
> D_status_obufpos
)
3885 size
= D_status_obufpos
;
3887 size
= write(D_userfd
, D_obuf
, size
);
3893 bcopy(D_obuf
+ size
, D_obuf
, len
);
3894 debug2("ASYNC: wrote %d - remaining %d\n", size
, len
);
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
3912 D_obuffree
= D_obuflen
= 0;
3914 gettimeofday(&D_status_time
, NULL
);
3915 SetTimeout(&D_statusev
, MsgWait
);
3918 RefreshBraille(); /* let user see multiple Msg()s */
3924 D_blocked_fuzz
-= size
;
3925 if (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
);
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
);
3946 Activate(D_fore
? D_fore
->w_norefresh
: 0);
3947 D_blocked_fuzz
= D_obufp
- D_obuf
;
3953 /* linux flow control is badly broken */
3954 if (errno
== EAGAIN
)
3957 D_writeev
.type
= EV_TIMEOUT
;
3958 D_writeev
.handler
= disp_writeev_eagain
;
3959 SetTimeout(&D_writeev
, 100);
3963 if (errno
!= EINTR
&& errno
!= EAGAIN
)
3964 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3965 if (errno
!= EWOULDBLOCK
)
3967 Msg(errno
, "Error writing output to display");
3972 disp_readev_fn(ev
, data
)
3980 display
= (struct display
*)data
;
3982 /* Hmmmm... a bit ugly... */
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
)
3991 display
= (struct display
*)data
;
3998 size
= sizeof(D_fore
->w_pwin
->p_inbuf
) - D_fore
->w_pwin
->p_inlen
;
4001 size
= sizeof(D_fore
->w_inbuf
) - D_fore
->w_inlen
;
4007 size
= 1; /* Always allow one char for command keys */
4009 size
= read(D_userfd
, buf
, size
);
4012 if (errno
== EINTR
|| errno
== EAGAIN
)
4014 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
4015 if (errno
== EWOULDBLOCK
)
4018 debug1("Read error: %d - hangup!\n", errno
);
4025 debug("Found EOF - hangup!\n");
4036 Activate(D_fore
? D_fore
->w_norefresh
: 0);
4041 if (D_blocked
> 1) /* 2, 3 */
4047 for (p
= windows
; p
; p
= p
->w_next
)
4048 if (p
->w_zdisplay
== display
)
4050 flayer
= &p
->w_layer
;
4053 LayProcess(&bufp
, &size
);
4056 debug("zmodem window gone, deblocking display");
4057 zmodem_abort(0, display
);
4063 D_fore
->w_lastdisp
= display
;
4064 if (D_mouse
&& D_forecv
)
4066 unsigned char *bp
= (unsigned char *)buf
;
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')
4077 else if (i
< 5 || bp
[0] != 0233 || bp
[1] != 'M')
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
)
4098 else if (D_mousetrack
&& bp
[2] == '#')
4100 /* 'focus' to the clicked region, only on mouse up */
4101 struct canvas
*cv
= FindCanvas(x
, y
);
4104 SetForeCanvas(display
, cv
);
4105 /* XXX: Do we want to reset the input buffer? */
4110 bcopy((char *)bp
+ 1, (char *)bp
, i
);
4115 bcopy((char *)bp
+ 5, (char *)bp
, i
- 5);
4122 if (D_encoding
!= (D_forecv
? D_forecv
->c_layer
->l_encoding
: 0))
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
);
4132 i
--; /* try char again */
4138 j
+= EncodeChar(buf2
+ j
, c
, enc
, &font
);
4139 j
+= EncodeChar(buf2
+ j
, -1, enc
, &font
);
4142 j
+= EncodeChar(buf2
+ j
, c
, enc
, 0);
4143 if (j
> (int)sizeof(buf2
) - 10) /* just in case... */
4146 (*D_processinput
)(buf2
, j
);
4150 (*D_processinput
)(buf
, size
);
4154 disp_status_fn(ev
, data
)
4158 display
= (struct display
*)data
;
4159 debug1("disp_status_fn for display %x\n", (int)display
);
4165 disp_hstatus_fn(ev
, data
)
4169 display
= (struct display
*)data
;
4170 if (D_status
== STATUS_ON_HS
)
4180 disp_blocked_fn(ev
, data
)
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");
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;
4203 cv_winid_fn(ev
, data
)
4208 struct canvas
*cv
= (struct canvas
*)data
;
4210 display
= cv
->c_display
;
4211 if (D_status
== STATUS_ON_WIN
)
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)
4227 disp_map_fn(ev
, data
)
4234 display
= (struct display
*)data
;
4235 debug("Flushing map sequence\n");
4238 p
= (char *)D_seqp
- l
;
4239 D_seqp
= D_kmaps
+ 3;
4241 if ((q
= 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);
4249 ProcessInput2((char *)q
+ 3, q
[2]);
4262 disp_idle_fn(ev
, data
)
4266 struct display
*olddisplay
;
4267 display
= (struct display
*)data
;
4268 debug("idle timeout\n");
4269 if (idletimo
<= 0 || idleaction
.nr
== RC_ILLEGAL
)
4271 olddisplay
= display
;
4272 flayer
= D_forecv
->c_layer
;
4274 DoAction(&idleaction
, -1);
4275 if (idleaction
.nr
== RC_BLANKER
)
4277 for (display
= displays
; display
; display
= display
->d_next
)
4278 if (olddisplay
== display
)
4289 SetTimeout(&D_idleev
, idletimo
);
4290 if (!D_idleev
.queued
)
4301 disp_blanker_fn(ev
, data
)
4305 char buf
[IOSIZE
], *b
;
4308 display
= (struct display
*)data
;
4309 size
= read(D_blankerev
.fd
, buf
, IOSIZE
);
4312 evdeq(&D_blankerev
);
4313 close(D_blankerev
.fd
);
4314 D_blankerev
.fd
= -1;
4317 for (b
= buf
; size
; size
--)
4324 int oldtop
= D_top
, oldbot
= D_bot
;
4325 struct mchar oldrend
;
4327 if (D_blankerev
.fd
== -1)
4331 evdeq(&D_blankerev
);
4332 close(D_blankerev
.fd
);
4333 D_blankerev
.fd
= -1;
4334 Kill(D_blankerpid
, SIGHUP
);
4346 AddStr("\033[m\033[m"); /* why is D_ME not set? */
4353 D_rend
= mchar_null
;
4357 ChangeScrollRegion(oldtop
, oldbot
);
4358 SetRendition(&oldrend
);
4371 char libuf
[20], cobuf
[20];
4375 strcpy(termname
, "TERM=");
4376 strncpy(termname
+ 5, D_termname
, sizeof(termname
) - 6);
4377 termname
[sizeof(termname
) - 1] = 0;
4380 if ((D_blankerev
.fd
= OpenPTY(&m
)) == -1)
4382 Msg(0, "OpenPty failed");
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;
4397 switch (pid
= (int)fork())
4401 close(D_blankerev
.fd
);
4402 D_blankerev
.fd
= -1;
4407 if (dfp
&& dfp
!= stderr
)
4413 if (setgid(real_gid
) || setuid(real_uid
))
4414 Panic(errno
, "setuid/setgid");
4420 closeallfiles(slave
);
4421 if (open(m
, O_RDWR
))
4422 Panic(errno
, "Cannot open %s", m
);
4429 SetTTY(0, &D_OldMode
);
4434 glwz
.ws_col
= D_width
;
4435 glwz
.ws_row
= D_height
;
4436 (void)ioctl(0, TIOCSWINSZ
, (char *)&glwz
);
4438 sprintf(libuf
, "LINES=%d", D_height
);
4439 sprintf(cobuf
, "COLUMNS=%d", D_width
);
4444 signal(SIGPIPE
, SIG_DFL
);
4447 execvpe(*cmdv
, cmdv
, NewEnv
+ 3);
4448 Panic(errno
, "%s", *cmdv
);
4453 evenq(&D_blankerev
);
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
;
4469 struct canvas
*cnext
, *c
= cv
;
4470 for (; cv
; cv
= cnext
)
4474 FreeLayoutCv(cv
->c_slperp
);
4478 cnext
= cv
->c_slnext
;
4486 DupLayoutCv(cvf
, cvt
, save
)
4487 struct canvas
*cvf
, *cvt
;
4492 cvt
->c_slorient
= cvf
->c_slorient
;
4493 cvt
->c_slweight
= cvf
->c_slweight
;
4494 if (cvf
== D_forecv
)
4498 cvt
->c_display
= display
;
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
;
4512 struct win
*p
= cvf
->c_layer
? Layer2Window(cvf
->c_layer
) : 0;
4513 cvt
->c_layer
= p
? &p
->w_layer
: 0;
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
);
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
;
4539 for (; cv
; cv
= cv
->c_slnext
)
4543 PutWindowCv(cv
->c_slperp
);
4546 p
= cv
->c_layer
? (struct win
*)cv
->c_layer
->l_data
: 0;
4548 SetCanvasWindow(cv
, p
);
4553 CreateLayout(title
, startat
)
4560 if (startat
>= MAXLAY
|| startat
< 0)
4562 for (i
= startat
; ;)
4570 Msg(0, "No more layouts\n");
4574 lay
= (struct layout
*)calloc(1, sizeof(*lay
));
4575 lay
->lay_title
= SaveStr(title
);
4576 lay
->lay_autosave
= 1;
4577 lay
->lay_number
= i
;
4579 lay
->lay_next
= layouts
;
4585 SaveLayout(name
, cv
)
4591 for (lay
= layouts
; lay
; lay
= lay
->lay_next
)
4592 if (!strcmp(lay
->lay_title
, name
))
4595 FreeLayoutCv(&lay
->lay_canvas
);
4597 lay
= CreateLayout(name
, 0);
4601 DupLayoutCv(cv
, &lay
->lay_canvas
, 1);
4602 lay
->lay_forecv
= D_forecv
;
4612 if (!lay
|| !lay
->lay_autosave
)
4614 FreeLayoutCv(&lay
->lay_canvas
);
4616 DupLayoutCv(&D_canvas
, &lay
->lay_canvas
, 1);
4617 lay
->lay_forecv
= D_forecv
;
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
)
4632 for (lay
= layouts
; lay
; lay
= lay
->lay_next
)
4633 if (!strcmp(lay
->lay_title
, name
))
4643 AutosaveLayout(D_layout
);
4646 while (D_canvas
.c_slperp
)
4647 FreeCanvas(D_canvas
.c_slperp
);
4648 MakeDefaultCanvas();
4649 SetCanvasWindow(D_forecv
, 0);
4653 while (D_canvas
.c_slperp
)
4654 FreeCanvas(D_canvas
.c_slperp
);
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();
4668 NewLayout(title
, startat
)
4675 lay
= CreateLayout(title
, startat
);
4678 LoadLayout(0, &D_canvas
);
4680 DupLayoutCv(&D_canvas
, &lay
->lay_canvas
, 1);
4681 lay
->lay_forecv
= D_forecv
;
4684 lay
->lay_autosave
= 1;
4688 AddLayoutsInfo(buf
, len
, where
)
4694 struct layout
*p
, **pp
;
4698 for (pp
= laytab
; pp
< laytab
+ MAXLAY
; pp
++)
4700 if (pp
- laytab
== where
&& ss
== buf
)
4708 if (s
- buf
+ l
> len
- 24)
4715 sprintf(s
, "%d", p
->lay_number
);
4716 if (p
->lay_number
== where
)
4719 if (display
&& p
== D_layout
)
4740 Msg(0, "No layouts defined\n");
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)
4750 if (s
- ss
< D_width
)
4766 struct layout
**layp
= &layouts
;
4768 for (; *layp
; layp
= &(*layp
)->lay_next
)
4772 *layp
= lay
->lay_next
;
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
);
4784 free(lay
->lay_title
);
4788 LoadLayout((display
&& D_layout
) ? D_layout
: *layp
? *layp
: layouts
,
4789 display
? &D_canvas
: (struct canvas
*)0);