1 /* Copyright (c) 1993-2002
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, see
18 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
21 ****************************************************************
24 #include <sys/types.h>
32 extern struct display
*display
, *displays
;
34 extern struct mline mline_blank
, mline_null
;
35 extern struct mchar mchar_blank
, mchar_null
;
37 extern struct layer
*flayer
; /* sigh */
38 extern struct LayFuncs WinLf
;
39 extern struct LayFuncs BlankLf
;
42 static struct mline
*mloff
__P((struct mline
*, int));
47 * ...here is all the clipping code... beware!
49 * XXX: add some speedup code!
58 static struct mline mml
;
62 mml
.image
= ml
->image
+ off
;
63 mml
.attr
= ml
->attr
+ off
;
65 mml
.font
= ml
->font
+ off
;
68 mml
.color
= ml
->color
+ off
;
70 mml
.colorx
= ml
->colorx
+ off
;
77 # define RECODE_MCHAR(mc) ((l->l_encoding == UTF8) != (D_encoding == UTF8) ? recode_mchar(mc, l->l_encoding, D_encoding) : (mc))
78 # define RECODE_MLINE(ml) ((l->l_encoding == UTF8) != (D_encoding == UTF8) ? recode_mline(ml, l->l_width, l->l_encoding, D_encoding) : (ml))
80 # define RECODE_MCHAR(mc) (mc)
81 # define RECODE_MLINE(ml) (ml)
98 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
100 display
= cv
->c_display
;
107 debug2("---LGotoPos %d %d\n", x2
, y2
);
116 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
118 if (x2
< vp
->v_xs
|| x2
> vp
->v_xe
)
120 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
129 LScrollH(l
, n
, y
, xs
, xe
, bce
, ol
)
141 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
142 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
145 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
147 xs2
= xs
+ vp
->v_xoff
;
148 xe2
= xe
+ vp
->v_xoff
;
155 display
= cv
->c_display
;
158 ScrollH(y2
, xs2
, xe2
, n
, bce
, ol
? mloff(ol
, -vp
->v_xoff
) : 0);
159 if (xe2
- xs2
== xe
- xs
)
164 xe2
= xe
+ vp
->v_xoff
- n
;
169 xs2
= xs
+ vp
->v_xoff
- n
;
176 RefreshArea(xs2
, y2
, xe2
, y2
, 1);
181 LScrollV(l
, n
, ys
, ye
, bce
)
189 int ys2
, ye2
, xs2
, xe2
;
192 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
193 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
196 xe2
= l
->l_width
- 1 + vp
->v_xoff
;
197 ys2
= ys
+ vp
->v_yoff
;
198 ye2
= ye
+ vp
->v_yoff
;
207 if (ys2
> ye2
|| xs2
> xe2
)
209 display
= cv
->c_display
;
213 ScrollV(xs2
, ys2
, xe2
, ye2
, n
, bce
);
215 ScrollV(vp
->v_xs
, ys2
, vp
->v_xe
, ye2
, n
, bce
);
217 debug2("LScrollV: %d %d", ys
, ye
);
218 debug2(" -> %d %d\n", ys2
, ye2
);
219 if (ye2
- ys2
== ye
- ys
)
224 ye2
= ye
+ vp
->v_yoff
- n
;
229 ys2
= ys
+ vp
->v_yoff
- n
;
231 debug2("LScrollV: - %d %d\n", ys2
, ye2
);
236 debug2("LScrollV: - %d %d\n", ys2
, ye2
);
238 RefreshArea(xs2
, ys2
, xe2
, ye2
, 1);
243 LInsChar(l
, c
, x
, y
, ol
)
252 struct mchar
*c2
, cc
;
255 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
256 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
259 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
261 xs2
= x
+ vp
->v_xoff
;
262 xe2
= l
->l_width
- 1 + vp
->v_xoff
;
272 i
= xs2
- vp
->v_xoff
- 1;
273 if (i
>= 0 && i
< l
->l_width
)
275 copy_mline2mchar(&cc
, ol
, i
);
286 display
= cv
->c_display
;
289 rol
= RECODE_MLINE(ol
);
290 InsChar(RECODE_MCHAR(c2
), xs2
, xe2
, y2
, mloff(rol
, -vp
->v_xoff
));
292 RefreshArea(xs2
, y2
, xs2
, y2
, 1);
306 if (bd
.bd_refreshing
)
308 BPutChar(l
, c
, x
, y
);
312 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
314 display
= cv
->c_display
;
317 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
320 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
323 if (x2
< vp
->v_xs
|| x2
> vp
->v_xe
)
325 PutChar(RECODE_MCHAR(c
), x2
, y2
);
332 LPutStr(l
, s
, n
, r
, x
, y
)
344 if (x
+ n
> l
->l_width
)
347 if (bd
.bd_refreshing
)
349 BPutStr(l
, s
, n
, r
, x
, y
);
353 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
354 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
357 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
359 xs2
= x
+ vp
->v_xoff
;
367 display
= cv
->c_display
;
372 s2
= s
+ xs2
- x
- vp
->v_xoff
;
374 if (D_encoding
== UTF8
&& l
->l_encoding
!= UTF8
&& (r
->font
|| l
->l_encoding
))
381 PutChar(RECODE_MCHAR(&mc
), xs2
++, y2
);
392 LPutWinMsg(l
, s
, n
, r
, x
, y
)
401 int xs2
, xe2
, y2
, len
, len2
;
404 if (x
+ n
> l
->l_width
)
407 if (bd
.bd_refreshing
)
409 BPutStr(l
, s
, n
, r
, x
, y
);
416 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
417 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
420 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
422 xs2
= x
+ vp
->v_xoff
;
430 display
= cv
->c_display
;
435 len2
= xe2
- (x
+ vp
->v_xoff
) + 1;
438 PutWinMsg(s
, xs2
- x
- vp
->v_xoff
, len2
);
439 xs2
= x
+ vp
->v_xoff
+ len2
;
451 LClearLine(l
, y
, xs
, xe
, bce
, ol
)
460 /* check for magic margin condition */
461 if (xs
>= l
->l_width
)
463 if (xe
>= l
->l_width
)
465 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
466 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
468 xs2
= xs
+ vp
->v_xoff
;
469 xe2
= xe
+ vp
->v_xoff
;
471 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
479 display
= cv
->c_display
;
482 ClearLine(ol
? mloff(RECODE_MLINE(ol
), -vp
->v_xoff
) : (struct mline
*)0, y2
, xs2
, xe2
, bce
);
487 LClearArea(l
, xs
, ys
, xe
, ye
, bce
, uself
)
495 int xs2
, ys2
, xe2
, ye2
;
497 if (bd
.bd_refreshing
)
500 /* check for magic margin condition */
501 if (xs
>= l
->l_width
)
503 if (xe
>= l
->l_width
)
505 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
507 display
= cv
->c_display
;
510 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
512 xs2
= xs
+ vp
->v_xoff
;
513 xe2
= xe
+ vp
->v_xoff
;
514 ys2
= ys
+ vp
->v_yoff
;
515 ye2
= ye
+ vp
->v_yoff
;
532 xce
= l
->l_width
- 1 + vp
->v_xoff
;
539 if (ys2
!= ys
+ vp
->v_yoff
)
541 if (ye2
!= ye
+ vp
->v_yoff
)
543 display
= cv
->c_display
;
544 ClearArea(xs2
, ys2
, xcs
, xce
, xe2
, ye2
, bce
, uself
);
546 if (xs
== 0 || ys2
!= ys
+ vp
->v_yoff
)
548 if (xe
== l
->l_width
- 1 || ye2
!= ye
+ vp
->v_yoff
)
550 display
= cv
->c_display
;
551 ClearArea(xs2
, ys2
, vp
->v_xs
, vp
->v_xe
, xe2
, ye2
, bce
, uself
);
558 LCDisplayLine(l
, ml
, y
, xs
, xe
, isblank
)
568 if (bd
.bd_refreshing
)
570 BCDisplayLine(l
, ml
, y
, xs
, xe
, isblank
);
574 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
576 display
= cv
->c_display
;
579 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
581 xs2
= xs
+ vp
->v_xoff
;
582 xe2
= xe
+ vp
->v_xoff
;
584 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
592 display
= cv
->c_display
;
593 debug3("LCDisplayLine: DisplayLine %d, %d-%d", y2
, xs2
, xe2
);
594 debug1(" mloff = %d\n", -vp
->v_xoff
);
595 DisplayLine(isblank
? &mline_blank
: &mline_null
, mloff(RECODE_MLINE(ml
), -vp
->v_xoff
), y2
, xs2
, xe2
);
601 LCDisplayLineWrap(l
, ml
, y
, from
, to
, isblank
)
608 copy_mline2mchar(&nc
, ml
, 0);
610 if (dw_left(ml
, 0, l
->l_encoding
))
612 nc
.mbcs
= ml
->image
[1];
616 LWrapChar(l
, &nc
, y
- 1, -1, -1, 0);
619 LCDisplayLine(l
, ml
, y
, from
, to
, isblank
);
629 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
631 display
= cv
->c_display
;
639 LWrapChar(l
, c
, y
, top
, bot
, ins
)
645 struct canvas
*cv
, *cvlist
, *cvlnext
;
646 struct viewport
*vp
, *evp
, **vpp
;
647 int yy
, y2
, yy2
, top2
, bot2
;
657 /* simple case: no scrolling */
659 /* cursor after wrapping */
660 yy
= y
== l
->l_height
- 1 ? y
: y
+ 1;
662 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
664 y2
= 0; /* gcc -Wall */
665 display
= cv
->c_display
;
668 /* find the viewport of the wrapped character */
669 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
672 yy2
= yy
+ vp
->v_yoff
;
673 if (yy2
>= vp
->v_ys
&& yy2
<= vp
->v_ye
&& vp
->v_xoff
>= vp
->v_xs
&& vp
->v_xoff
<= vp
->v_xe
)
677 continue; /* nothing to do, character not visible */
678 /* find the viewport of the character at the end of the line*/
679 for (evp
= cv
->c_vplist
; evp
; evp
= evp
->v_next
)
680 if (y2
>= evp
->v_ys
&& y2
<= evp
->v_ye
&& evp
->v_xoff
+ l
->l_width
- 1 >= evp
->v_xs
&& evp
->v_xoff
+ l
->l_width
- 1 <= evp
->v_xe
)
682 if (evp
== 0 || (ins
&& vp
->v_xoff
+ l
->l_width
- 1 > vp
->v_ye
))
684 /* no wrapping possible */
685 debug("LWrap: can't wrap!\n");
686 cvlist
= l
->l_cvlist
;
687 cvlnext
= cv
->c_lnext
;
691 LInsChar(l
, c
, 0, yy
, 0);
693 LPutChar(l
, c
, 0, yy
);
694 l
->l_cvlist
= cvlist
;
695 cv
->c_lnext
= cvlnext
;
699 WrapChar(RECODE_MCHAR(c
), vp
->v_xoff
+ l
->l_width
, y2
, vp
->v_xoff
, -1, vp
->v_xoff
+ l
->l_width
- 1, -1, ins
);
705 /* hard case: scroll up*/
707 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
709 display
= cv
->c_display
;
712 /* search for wrap viewport */
713 for (vpp
= &cv
->c_vplist
; (vp
= *vpp
); vpp
= &vp
->v_next
)
715 yy2
= bot
+ vp
->v_yoff
;
716 if (yy2
>= vp
->v_ys
&& yy2
<= vp
->v_ye
&& vp
->v_xoff
>= vp
->v_xs
&& vp
->v_xoff
+ l
->l_width
- 1 <= vp
->v_xe
)
722 /* great, can use Wrap on the vp */
723 /* temporarily remove vp from cvlist */
728 /* scroll all viewports != vp */
729 cvlist
= l
->l_cvlist
;
730 cvlnext
= cv
->c_lnext
;
733 LScrollV(l
, 1, top
, bot
, bce
);
737 LInsChar(l
, c
, 0, bot
, 0);
739 LPutChar(l
, c
, 0, bot
);
741 l
->l_cvlist
= cvlist
;
742 cv
->c_lnext
= cvlnext
;
746 /* add vp back to cvlist */
748 top2
= top
+ vp
->v_yoff
;
749 bot2
= bot
+ vp
->v_yoff
;
752 WrapChar(RECODE_MCHAR(c
), vp
->v_xoff
+ l
->l_width
, bot2
, vp
->v_xoff
, top2
, vp
->v_xoff
+ l
->l_width
- 1, bot2
, ins
);
760 LCursorVisibility(l
, vis
)
765 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
767 display
= cv
->c_display
;
772 CursorVisibility(vis
);
782 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
784 display
= cv
->c_display
;
797 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
799 display
= cv
->c_display
;
809 LCursorkeysMode(l
, on
)
814 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
816 display
= cv
->c_display
;
831 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
833 display
= cv
->c_display
;
847 LClearArea(l
, 0, 0, l
->l_width
- 1, l
->l_height
- 1, 0, uself
);
851 LRefreshAll(l
, isblank
)
855 struct layer
*oldflayer
;
858 debug1("LRefreshAll isblank=%d\n", isblank
);
862 LClearArea(l
, 0, 0, l
->l_width
- 1, l
->l_height
- 1, 0, 0);
863 /* signal full refresh */
864 LayRedisplayLine(-1, -1, -1, 1);
865 for (y
= 0; y
< l
->l_height
; y
++)
866 LayRedisplayLine(y
, 0, l
->l_width
- 1, 1);
872 #if defined(USEVARARGS) && defined(__STDC__)
873 LMsg(int err
, char *fmt
, VA_DOTS
)
875 LMsg(err
, fmt
, VA_DOTS
)
882 char buf
[MAXPATHLEN
*2];
888 (void)vsnprintf(p
, sizeof(buf
) - 100, fmt
, VA_ARGS(ap
));
895 strncpy(p
, strerror(err
), buf
+ sizeof(buf
) - p
- 1);
896 buf
[sizeof(buf
) - 1] = 0;
898 debug2("LMsg('%s') (%#x);\n", buf
, (unsigned int)flayer
);
899 for (display
= displays
; display
; display
= display
->d_next
)
901 for (cv
= D_cvlist
; cv
; cv
= cv
->c_next
)
902 if (cv
->c_layer
== flayer
)
911 /*******************************************************************/
912 /*******************************************************************/
915 * Layer creation / removal
922 struct canvas
*cv
, *ncv
;
923 struct layer
*l
, *oldflayer
;
926 debug1("KillLayerChain %#x\n", lay
);
927 for (l
= lay
; l
; l
= l
->l_next
)
929 if (l
->l_layfn
== &WinLf
|| l
->l_layfn
== &BlankLf
)
931 debug1("- killing %#x\n", l
);
934 for (cv
= l
->l_cvlist
; cv
; cv
= ncv
)
950 InitOverlayPage(datasize
, lf
, block
)
956 struct layer
*newlay
;
957 struct canvas
*cv
, *cvp
, **cvpp
;
963 if (display
&& D_forecv
->c_layer
== flayer
)
964 cv
= D_forecv
; /* work only on this cv! */
966 if ((newlay
= (struct layer
*)calloc(1, sizeof(struct layer
))) == 0)
968 Msg(0, "No memory for layer struct");
971 debug2("Entering new layer on top of %#x: %#x\n", (unsigned int)flayer
, newlay
);
975 if ((data
= malloc(datasize
)) == 0)
977 free((char *)newlay
);
978 Msg(0, "No memory for layer data");
981 bzero(data
, datasize
);
984 p
= Layer2Window(flayer
);
986 if (p
&& (p
->w_savelayer
== flayer
|| (block
&& flayer
->l_next
== 0)))
988 if (p
->w_savelayer
&& p
->w_savelayer
!= flayer
&& p
->w_savelayer
->l_cvlist
== 0)
989 KillLayerChain(p
->w_savelayer
);
990 p
->w_savelayer
= newlay
;
993 if (cv
&& flayer
->l_next
== 0 && !block
)
995 struct display
*olddisplay
= display
;
996 display
= cv
->c_display
;
998 display
= olddisplay
;
1000 /* new branch -> just get canvas vps */
1001 for (cvpp
= &flayer
->l_cvlist
; (cvp
= *cvpp
); cvpp
= &cvp
->c_lnext
)
1005 *cvpp
= cv
->c_lnext
;
1006 newlay
->l_cvlist
= cv
;
1008 cv
->c_layer
= newlay
;
1012 LAY_DISPLAYS(flayer
, RemoveStatus());
1014 debug("layer is blocking\n");
1015 if (block
&& flayer
->l_layfn
== &WinLf
)
1017 debug("...and is first, so window gets blocked\n");
1018 ASSERT(p
->w_blocked
== 0);
1020 newlay
->l_blocking
= 1;
1022 /* change all canvases */
1023 newlay
->l_cvlist
= flayer
->l_cvlist
;
1024 for (cvp
= newlay
->l_cvlist
; cvp
; cvp
= cvp
->c_lnext
)
1025 cvp
->c_layer
= newlay
;
1026 flayer
->l_cvlist
= 0;
1028 newlay
->l_width
= flayer
->l_width
;
1029 newlay
->l_height
= flayer
->l_height
;
1030 newlay
->l_encoding
= 0;
1031 newlay
->l_layfn
= lf
;
1032 newlay
->l_data
= data
;
1033 newlay
->l_next
= flayer
;
1034 newlay
->l_bottom
= flayer
->l_bottom
;
1040 extern struct layout
*layouts
;
1045 struct layer
*oldlay
;
1047 int doredisplay
= 0;
1048 struct canvas
*cv
, *ocv
;
1052 debug1("Exiting layer %#x\n", (unsigned int)flayer
);
1055 free(oldlay
->l_data
);
1057 p
= Layer2Window(flayer
);
1059 flayer
= oldlay
->l_next
;
1060 if (flayer
->l_layfn
== &WinLf
)
1062 if (oldlay
->l_blocking
)
1064 ASSERT(p
->w_blocked
> 0);
1066 debug1("layer was blocking, -> w_blocked now %d\n", p
->w_blocked
);
1068 /* don't warp dead layers: check cvlist */
1069 if (p
->w_blocked
&& p
->w_savelayer
&& p
->w_savelayer
!= flayer
&& oldlay
->l_cvlist
)
1071 debug("warping to top of blocking chain!\n");
1072 /* warp ourself into savelayer */
1073 flayer
= p
->w_savelayer
;
1077 if (p
&& p
->w_savelayer
== oldlay
)
1078 p
->w_savelayer
= flayer
;
1080 if (p
&& oldlay
== p
->w_paster
.pa_pastelayer
)
1081 p
->w_paster
.pa_pastelayer
= 0;
1084 for (lay
= layouts
; lay
; lay
= lay
->lay_next
)
1085 for (cv
= lay
->lay_cvlist
; cv
; cv
= cv
->c_next
)
1086 if (cv
->c_layer
== oldlay
)
1087 cv
->c_layer
= flayer
;
1089 /* add all canvases back into next layer's canvas list */
1090 for (ocv
= 0, cv
= oldlay
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
1092 cv
->c_layer
= flayer
;
1097 cv
= flayer
->l_cvlist
;
1099 flayer
->l_cvlist
= oldlay
->l_cvlist
;
1100 /* redisplay only the warped cvs */
1102 LRefreshAll(flayer
, 0);
1105 oldlay
->l_cvlist
= 0;
1106 free((char *)oldlay
);