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 2, 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, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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
)
402 int xs2
, xe2
, y2
, len
, len2
;
405 if (x
+ n
> l
->l_width
)
408 if (bd
.bd_refreshing
)
410 BPutStr(l
, s
, n
, r
, x
, y
);
417 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
418 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
421 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
423 xs2
= x
+ vp
->v_xoff
;
431 display
= cv
->c_display
;
436 len2
= xe2
- (x
+ vp
->v_xoff
) + 1;
439 PutWinMsg(s
, xs2
- x
- vp
->v_xoff
, len2
);
440 xs2
= x
+ vp
->v_xoff
+ len2
;
452 LClearLine(l
, y
, xs
, xe
, bce
, ol
)
461 /* check for magic margin condition */
462 if (xs
>= l
->l_width
)
464 if (xe
>= l
->l_width
)
466 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
467 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
469 xs2
= xs
+ vp
->v_xoff
;
470 xe2
= xe
+ vp
->v_xoff
;
472 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
480 display
= cv
->c_display
;
483 ClearLine(ol
? mloff(RECODE_MLINE(ol
), -vp
->v_xoff
) : (struct mline
*)0, y2
, xs2
, xe2
, bce
);
488 LClearArea(l
, xs
, ys
, xe
, ye
, bce
, uself
)
496 int xs2
, ys2
, xe2
, ye2
;
498 if (bd
.bd_refreshing
)
501 /* check for magic margin condition */
502 if (xs
>= l
->l_width
)
504 if (xe
>= l
->l_width
)
506 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
508 display
= cv
->c_display
;
511 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
513 xs2
= xs
+ vp
->v_xoff
;
514 xe2
= xe
+ vp
->v_xoff
;
515 ys2
= ys
+ vp
->v_yoff
;
516 ye2
= ye
+ vp
->v_yoff
;
533 xce
= l
->l_width
- 1 + vp
->v_xoff
;
540 if (ys2
!= ys
+ vp
->v_yoff
)
542 if (ye2
!= ye
+ vp
->v_yoff
)
544 display
= cv
->c_display
;
545 ClearArea(xs2
, ys2
, xcs
, xce
, xe2
, ye2
, bce
, uself
);
547 if (xs
== 0 || ys2
!= ys
+ vp
->v_yoff
)
549 if (xe
== l
->l_width
- 1 || ye2
!= ye
+ vp
->v_yoff
)
551 display
= cv
->c_display
;
552 ClearArea(xs2
, ys2
, vp
->v_xs
, vp
->v_xe
, xe2
, ye2
, bce
, uself
);
559 LCDisplayLine(l
, ml
, y
, xs
, xe
, isblank
)
569 if (bd
.bd_refreshing
)
571 BCDisplayLine(l
, ml
, y
, xs
, xe
, isblank
);
575 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
577 display
= cv
->c_display
;
580 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
582 xs2
= xs
+ vp
->v_xoff
;
583 xe2
= xe
+ vp
->v_xoff
;
585 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
593 display
= cv
->c_display
;
594 debug3("LCDisplayLine: DisplayLine %d, %d-%d", y2
, xs2
, xe2
);
595 debug1(" mloff = %d\n", -vp
->v_xoff
);
596 DisplayLine(isblank
? &mline_blank
: &mline_null
, mloff(RECODE_MLINE(ml
), -vp
->v_xoff
), y2
, xs2
, xe2
);
602 LCDisplayLineWrap(l
, ml
, y
, from
, to
, isblank
)
609 copy_mline2mchar(&nc
, ml
, 0);
611 if (dw_left(ml
, 0, l
->l_encoding
))
613 nc
.mbcs
= ml
->image
[1];
617 LWrapChar(l
, &nc
, y
- 1, -1, -1, 0);
620 LCDisplayLine(l
, ml
, y
, from
, to
, isblank
);
630 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
632 display
= cv
->c_display
;
640 LWrapChar(l
, c
, y
, top
, bot
, ins
)
646 struct canvas
*cv
, *cvlist
, *cvlnext
;
647 struct viewport
*vp
, *evp
, **vpp
;
648 int yy
, y2
, yy2
, top2
, bot2
;
658 /* simple case: no scrolling */
660 /* cursor after wrapping */
661 yy
= y
== l
->l_height
- 1 ? y
: y
+ 1;
663 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
665 y2
= 0; /* gcc -Wall */
666 display
= cv
->c_display
;
669 /* find the viewport of the wrapped character */
670 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
673 yy2
= yy
+ vp
->v_yoff
;
674 if (yy2
>= vp
->v_ys
&& yy2
<= vp
->v_ye
&& vp
->v_xoff
>= vp
->v_xs
&& vp
->v_xoff
<= vp
->v_xe
)
678 continue; /* nothing to do, character not visible */
679 /* find the viewport of the character at the end of the line*/
680 for (evp
= cv
->c_vplist
; evp
; evp
= evp
->v_next
)
681 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
)
683 if (evp
== 0 || (ins
&& vp
->v_xoff
+ l
->l_width
- 1 > vp
->v_ye
))
685 /* no wrapping possible */
686 debug("LWrap: can't wrap!\n");
687 cvlist
= l
->l_cvlist
;
688 cvlnext
= cv
->c_lnext
;
692 LInsChar(l
, c
, 0, yy
, 0);
694 LPutChar(l
, c
, 0, yy
);
695 l
->l_cvlist
= cvlist
;
696 cv
->c_lnext
= cvlnext
;
700 WrapChar(RECODE_MCHAR(c
), vp
->v_xoff
+ l
->l_width
, y2
, vp
->v_xoff
, -1, vp
->v_xoff
+ l
->l_width
- 1, -1, ins
);
706 /* hard case: scroll up*/
708 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
710 display
= cv
->c_display
;
713 /* search for wrap viewport */
714 for (vpp
= &cv
->c_vplist
; (vp
= *vpp
); vpp
= &vp
->v_next
)
716 yy2
= bot
+ vp
->v_yoff
;
717 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
)
723 /* great, can use Wrap on the vp */
724 /* temporarily remove vp from cvlist */
729 /* scroll all viewports != vp */
730 cvlist
= l
->l_cvlist
;
731 cvlnext
= cv
->c_lnext
;
734 LScrollV(l
, 1, top
, bot
, bce
);
738 LInsChar(l
, c
, 0, bot
, 0);
740 LPutChar(l
, c
, 0, bot
);
742 l
->l_cvlist
= cvlist
;
743 cv
->c_lnext
= cvlnext
;
747 /* add vp back to cvlist */
749 top2
= top
+ vp
->v_yoff
;
750 bot2
= bot
+ vp
->v_yoff
;
753 WrapChar(RECODE_MCHAR(c
), vp
->v_xoff
+ l
->l_width
, bot2
, vp
->v_xoff
, top2
, vp
->v_xoff
+ l
->l_width
- 1, bot2
, ins
);
761 LCursorVisibility(l
, vis
)
766 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
768 display
= cv
->c_display
;
773 CursorVisibility(vis
);
783 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
785 display
= cv
->c_display
;
798 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
800 display
= cv
->c_display
;
810 LCursorkeysMode(l
, on
)
815 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
817 display
= cv
->c_display
;
832 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
834 display
= cv
->c_display
;
848 LClearArea(l
, 0, 0, l
->l_width
- 1, l
->l_height
- 1, 0, uself
);
852 LRefreshAll(l
, isblank
)
856 struct layer
*oldflayer
;
859 debug1("LRefreshAll isblank=%d\n", isblank
);
863 LClearArea(l
, 0, 0, l
->l_width
- 1, l
->l_height
- 1, 0, 0);
864 /* signal full refresh */
865 LayRedisplayLine(-1, -1, -1, 1);
866 for (y
= 0; y
< l
->l_height
; y
++)
867 LayRedisplayLine(y
, 0, l
->l_width
- 1, 1);
873 #if defined(USEVARARGS) && defined(__STDC__)
874 LMsg(int err
, char *fmt
, VA_DOTS
)
876 LMsg(err
, fmt
, VA_DOTS
)
883 char buf
[MAXPATHLEN
*2];
889 (void)vsnprintf(p
, sizeof(buf
) - 100, fmt
, VA_ARGS(ap
));
896 strncpy(p
, strerror(err
), buf
+ sizeof(buf
) - p
- 1);
897 buf
[sizeof(buf
) - 1] = 0;
899 debug2("LMsg('%s') (%#x);\n", buf
, (unsigned int)flayer
);
900 for (display
= displays
; display
; display
= display
->d_next
)
902 for (cv
= D_cvlist
; cv
; cv
= cv
->c_next
)
903 if (cv
->c_layer
== flayer
)
912 /*******************************************************************/
913 /*******************************************************************/
916 * Layer creation / removal
923 struct canvas
*cv
, *ncv
;
924 struct layer
*l
, *oldflayer
;
927 debug1("KillLayerChain %#x\n", lay
);
928 for (l
= lay
; l
; l
= l
->l_next
)
930 if (l
->l_layfn
== &WinLf
|| l
->l_layfn
== &BlankLf
)
932 debug1("- killing %#x\n", l
);
935 for (cv
= l
->l_cvlist
; cv
; cv
= ncv
)
951 InitOverlayPage(datasize
, lf
, block
)
957 struct layer
*newlay
;
958 struct canvas
*cv
, *cvp
, **cvpp
;
964 if (display
&& D_forecv
->c_layer
== flayer
)
965 cv
= D_forecv
; /* work only on this cv! */
967 if ((newlay
= (struct layer
*)calloc(1, sizeof(struct layer
))) == 0)
969 Msg(0, "No memory for layer struct");
972 debug2("Entering new layer on top of %#x: %#x\n", (unsigned int)flayer
, newlay
);
976 if ((data
= malloc(datasize
)) == 0)
978 free((char *)newlay
);
979 Msg(0, "No memory for layer data");
982 bzero(data
, datasize
);
985 p
= Layer2Window(flayer
);
987 if (p
&& (p
->w_savelayer
== flayer
|| (block
&& flayer
->l_next
== 0)))
989 if (p
->w_savelayer
&& p
->w_savelayer
!= flayer
&& p
->w_savelayer
->l_cvlist
== 0)
990 KillLayerChain(p
->w_savelayer
);
991 p
->w_savelayer
= newlay
;
994 if (cv
&& flayer
->l_next
== 0 && !block
)
996 struct display
*olddisplay
= display
;
997 display
= cv
->c_display
;
999 display
= olddisplay
;
1001 /* new branch -> just get canvas vps */
1002 for (cvpp
= &flayer
->l_cvlist
; (cvp
= *cvpp
); cvpp
= &cvp
->c_lnext
)
1006 *cvpp
= cv
->c_lnext
;
1007 newlay
->l_cvlist
= cv
;
1009 cv
->c_layer
= newlay
;
1013 LAY_DISPLAYS(flayer
, RemoveStatus());
1015 debug("layer is blocking\n");
1016 if (block
&& flayer
->l_layfn
== &WinLf
)
1018 debug("...and is first, so window gets blocked\n");
1019 ASSERT(p
->w_blocked
== 0);
1021 newlay
->l_blocking
= 1;
1023 /* change all canvases */
1024 newlay
->l_cvlist
= flayer
->l_cvlist
;
1025 for (cvp
= newlay
->l_cvlist
; cvp
; cvp
= cvp
->c_lnext
)
1026 cvp
->c_layer
= newlay
;
1027 flayer
->l_cvlist
= 0;
1029 newlay
->l_width
= flayer
->l_width
;
1030 newlay
->l_height
= flayer
->l_height
;
1031 newlay
->l_encoding
= 0;
1032 newlay
->l_layfn
= lf
;
1033 newlay
->l_data
= data
;
1034 newlay
->l_next
= flayer
;
1035 newlay
->l_bottom
= flayer
->l_bottom
;
1041 extern struct layout
*layouts
;
1046 struct layer
*oldlay
;
1048 int doredisplay
= 0;
1049 struct canvas
*cv
, *ocv
;
1053 debug1("Exiting layer %#x\n", (unsigned int)flayer
);
1056 free(oldlay
->l_data
);
1058 p
= Layer2Window(flayer
);
1060 flayer
= oldlay
->l_next
;
1061 if (flayer
->l_layfn
== &WinLf
)
1063 if (oldlay
->l_blocking
)
1065 ASSERT(p
->w_blocked
> 0);
1067 debug1("layer was blocking, -> w_blocked now %d\n", p
->w_blocked
);
1069 /* don't warp dead layers: check cvlist */
1070 if (p
->w_blocked
&& p
->w_savelayer
&& p
->w_savelayer
!= flayer
&& oldlay
->l_cvlist
)
1072 debug("warping to top of blocking chain!\n");
1073 /* warp ourself into savelayer */
1074 flayer
= p
->w_savelayer
;
1078 if (p
&& p
->w_savelayer
== oldlay
)
1079 p
->w_savelayer
= flayer
;
1081 if (p
&& oldlay
== p
->w_paster
.pa_pastelayer
)
1082 p
->w_paster
.pa_pastelayer
= 0;
1085 for (lay
= layouts
; lay
; lay
= lay
->lay_next
)
1086 for (cv
= lay
->lay_cvlist
; cv
; cv
= cv
->c_next
)
1087 if (cv
->c_layer
== oldlay
)
1088 cv
->c_layer
= flayer
;
1090 /* add all canvases back into next layer's canvas list */
1091 for (ocv
= 0, cv
= oldlay
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
1093 cv
->c_layer
= flayer
;
1098 cv
= flayer
->l_cvlist
;
1100 flayer
->l_cvlist
= oldlay
->l_cvlist
;
1101 /* redisplay only the warped cvs */
1103 LRefreshAll(flayer
, 0);
1106 oldlay
->l_cvlist
= 0;
1107 free((char *)oldlay
);