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>
37 extern struct display
*display
, *displays
;
39 extern struct mline mline_blank
, mline_null
;
40 extern struct mchar mchar_blank
, mchar_null
;
42 extern struct layer
*flayer
; /* sigh */
43 extern struct LayFuncs WinLf
;
44 extern struct LayFuncs BlankLf
;
47 static struct mline
*mloff
__P((struct mline
*, int));
52 * ...here is all the clipping code... beware!
54 * XXX: add some speedup code!
63 static struct mline mml
;
67 mml
.image
= ml
->image
+ off
;
68 mml
.attr
= ml
->attr
+ off
;
70 mml
.font
= ml
->font
+ off
;
73 mml
.color
= ml
->color
+ off
;
75 mml
.colorx
= ml
->colorx
+ off
;
82 # define RECODE_MCHAR(mc) ((l->l_encoding == UTF8) != (D_encoding == UTF8) ? recode_mchar(mc, l->l_encoding, D_encoding) : (mc))
83 # define RECODE_MLINE(ml) ((l->l_encoding == UTF8) != (D_encoding == UTF8) ? recode_mline(ml, l->l_width, l->l_encoding, D_encoding) : (ml))
85 # define RECODE_MCHAR(mc) (mc)
86 # define RECODE_MLINE(ml) (ml)
100 if (bd
.bd_refreshing
)
103 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
105 display
= cv
->c_display
;
112 debug2("---LGotoPos %d %d\n", x2
, y2
);
121 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
123 if (x2
< vp
->v_xs
|| x2
> vp
->v_xe
)
125 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
134 LScrollH(l
, n
, y
, xs
, xe
, bce
, ol
)
146 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
147 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
150 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
152 xs2
= xs
+ vp
->v_xoff
;
153 xe2
= xe
+ vp
->v_xoff
;
160 display
= cv
->c_display
;
163 ScrollH(y2
, xs2
, xe2
, n
, bce
, ol
? mloff(ol
, -vp
->v_xoff
) : 0);
164 if (xe2
- xs2
== xe
- xs
)
169 xe2
= xe
+ vp
->v_xoff
- n
;
174 xs2
= xs
+ vp
->v_xoff
- n
;
181 RefreshArea(xs2
, y2
, xe2
, y2
, 1);
186 LScrollV(l
, n
, ys
, ye
, bce
)
194 int ys2
, ye2
, xs2
, xe2
;
197 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
198 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
201 xe2
= l
->l_width
- 1 + vp
->v_xoff
;
202 ys2
= ys
+ vp
->v_yoff
;
203 ye2
= ye
+ vp
->v_yoff
;
212 if (ys2
> ye2
|| xs2
> xe2
)
214 display
= cv
->c_display
;
218 ScrollV(xs2
, ys2
, xe2
, ye2
, n
, bce
);
220 ScrollV(vp
->v_xs
, ys2
, vp
->v_xe
, ye2
, n
, bce
);
222 debug2("LScrollV: %d %d", ys
, ye
);
223 debug2(" -> %d %d\n", ys2
, ye2
);
224 if (ye2
- ys2
== ye
- ys
)
229 ye2
= ye
+ vp
->v_yoff
- n
;
234 ys2
= ys
+ vp
->v_yoff
- n
;
236 debug2("LScrollV: - %d %d\n", ys2
, ye2
);
241 debug2("LScrollV: - %d %d\n", ys2
, ye2
);
243 RefreshArea(xs2
, ys2
, xe2
, ye2
, 1);
248 LInsChar(l
, c
, x
, y
, ol
)
257 struct mchar
*c2
, cc
;
260 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
261 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
264 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
266 xs2
= x
+ vp
->v_xoff
;
267 xe2
= l
->l_width
- 1 + vp
->v_xoff
;
277 i
= xs2
- vp
->v_xoff
- 1;
278 if (i
>= 0 && i
< l
->l_width
)
280 copy_mline2mchar(&cc
, ol
, i
);
291 display
= cv
->c_display
;
294 rol
= RECODE_MLINE(ol
);
295 InsChar(RECODE_MCHAR(c2
), xs2
, xe2
, y2
, mloff(rol
, -vp
->v_xoff
));
297 RefreshArea(xs2
, y2
, xs2
, y2
, 1);
311 if (bd
.bd_refreshing
)
313 BPutChar(l
, c
, x
, y
);
317 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
319 display
= cv
->c_display
;
322 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
325 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
328 if (x2
< vp
->v_xs
|| x2
> vp
->v_xe
)
330 PutChar(RECODE_MCHAR(c
), x2
, y2
);
337 LPutStr(l
, s
, n
, r
, x
, y
)
349 if (x
+ n
> l
->l_width
)
352 if (bd
.bd_refreshing
)
354 BPutStr(l
, s
, n
, r
, x
, y
);
358 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
359 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
362 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
364 xs2
= x
+ vp
->v_xoff
;
372 display
= cv
->c_display
;
377 s2
= s
+ xs2
- x
- vp
->v_xoff
;
379 if (D_encoding
== UTF8
&& l
->l_encoding
!= UTF8
&& (r
->font
|| l
->l_encoding
))
386 PutChar(RECODE_MCHAR(&mc
), xs2
++, y2
);
397 LPutWinMsg(l
, s
, n
, r
, x
, y
)
406 int xs2
, xe2
, y2
, len
, len2
;
409 if (x
+ n
> l
->l_width
)
412 if (bd
.bd_refreshing
)
414 BPutStr(l
, s
, n
, r
, x
, y
);
421 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
422 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
425 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
427 xs2
= x
+ vp
->v_xoff
;
435 display
= cv
->c_display
;
440 len2
= xe2
- (x
+ vp
->v_xoff
) + 1;
443 PutWinMsg(s
, xs2
- x
- vp
->v_xoff
, len2
);
444 xs2
= x
+ vp
->v_xoff
+ len2
;
456 LClearLine(l
, y
, xs
, xe
, bce
, ol
)
465 /* check for magic margin condition */
466 if (xs
>= l
->l_width
)
468 if (xe
>= l
->l_width
)
470 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
471 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
473 xs2
= xs
+ vp
->v_xoff
;
474 xe2
= xe
+ vp
->v_xoff
;
476 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
484 display
= cv
->c_display
;
487 ClearLine(ol
? mloff(RECODE_MLINE(ol
), -vp
->v_xoff
) : (struct mline
*)0, y2
, xs2
, xe2
, bce
);
492 LClearArea(l
, xs
, ys
, xe
, ye
, bce
, uself
)
500 int xs2
, ys2
, xe2
, ye2
;
502 if (bd
.bd_refreshing
)
505 /* Check for zero-height window */
506 if (ys
< 0 || ye
< ys
)
509 /* check for magic margin condition */
510 if (xs
>= l
->l_width
)
512 if (xe
>= l
->l_width
)
514 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
516 display
= cv
->c_display
;
519 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
521 xs2
= xs
+ vp
->v_xoff
;
522 xe2
= xe
+ vp
->v_xoff
;
523 ys2
= ys
+ vp
->v_yoff
;
524 ye2
= ye
+ vp
->v_yoff
;
541 xce
= l
->l_width
- 1 + vp
->v_xoff
;
548 if (ys2
!= ys
+ vp
->v_yoff
)
550 if (ye2
!= ye
+ vp
->v_yoff
)
552 display
= cv
->c_display
;
553 ClearArea(xs2
, ys2
, xcs
, xce
, xe2
, ye2
, bce
, uself
);
555 if (xs
== 0 || ys2
!= ys
+ vp
->v_yoff
)
557 if (xe
== l
->l_width
- 1 || ye2
!= ye
+ vp
->v_yoff
)
559 display
= cv
->c_display
;
560 ClearArea(xs2
, ys2
, vp
->v_xs
, vp
->v_xe
, xe2
, ye2
, bce
, uself
);
567 LCDisplayLine(l
, ml
, y
, xs
, xe
, isblank
)
577 if (bd
.bd_refreshing
)
579 BCDisplayLine(l
, ml
, y
, xs
, xe
, isblank
);
583 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
585 display
= cv
->c_display
;
588 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
590 xs2
= xs
+ vp
->v_xoff
;
591 xe2
= xe
+ vp
->v_xoff
;
593 if (y2
< vp
->v_ys
|| y2
> vp
->v_ye
)
601 display
= cv
->c_display
;
602 debug3("LCDisplayLine: DisplayLine %d, %d-%d", y2
, xs2
, xe2
);
603 debug1(" mloff = %d\n", -vp
->v_xoff
);
604 DisplayLine(isblank
? &mline_blank
: &mline_null
, mloff(RECODE_MLINE(ml
), -vp
->v_xoff
), y2
, xs2
, xe2
);
610 LCDisplayLineWrap(l
, ml
, y
, from
, to
, isblank
)
617 copy_mline2mchar(&nc
, ml
, 0);
619 if (dw_left(ml
, 0, l
->l_encoding
))
621 nc
.mbcs
= ml
->image
[1];
625 LWrapChar(l
, &nc
, y
- 1, -1, -1, 0);
628 LCDisplayLine(l
, ml
, y
, from
, to
, isblank
);
638 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
640 display
= cv
->c_display
;
648 LWrapChar(l
, c
, y
, top
, bot
, ins
)
654 struct canvas
*cv
, *cvlist
, *cvlnext
;
655 struct viewport
*vp
, *evp
, **vpp
;
656 int yy
, y2
, yy2
, top2
, bot2
;
666 /* simple case: no scrolling */
668 /* cursor after wrapping */
669 yy
= y
== l
->l_height
- 1 ? y
: y
+ 1;
671 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
673 y2
= 0; /* gcc -Wall */
674 display
= cv
->c_display
;
677 /* find the viewport of the wrapped character */
678 for (vp
= cv
->c_vplist
; vp
; vp
= vp
->v_next
)
681 yy2
= yy
+ vp
->v_yoff
;
682 if (yy2
>= vp
->v_ys
&& yy2
<= vp
->v_ye
&& vp
->v_xoff
>= vp
->v_xs
&& vp
->v_xoff
<= vp
->v_xe
)
686 continue; /* nothing to do, character not visible */
687 /* find the viewport of the character at the end of the line*/
688 for (evp
= cv
->c_vplist
; evp
; evp
= evp
->v_next
)
689 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
)
691 if (evp
== 0 || (ins
&& vp
->v_xoff
+ l
->l_width
- 1 > vp
->v_ye
))
693 /* no wrapping possible */
694 debug("LWrap: can't wrap!\n");
695 cvlist
= l
->l_cvlist
;
696 cvlnext
= cv
->c_lnext
;
700 LInsChar(l
, c
, 0, yy
, 0);
702 LPutChar(l
, c
, 0, yy
);
703 l
->l_cvlist
= cvlist
;
704 cv
->c_lnext
= cvlnext
;
708 WrapChar(RECODE_MCHAR(c
), vp
->v_xoff
+ l
->l_width
, y2
, vp
->v_xoff
, -1, vp
->v_xoff
+ l
->l_width
- 1, -1, ins
);
714 /* hard case: scroll up*/
716 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
718 display
= cv
->c_display
;
721 /* search for wrap viewport */
722 for (vpp
= &cv
->c_vplist
; (vp
= *vpp
); vpp
= &vp
->v_next
)
724 yy2
= bot
+ vp
->v_yoff
;
725 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
)
731 /* great, can use Wrap on the vp */
732 /* temporarily remove vp from cvlist */
737 /* scroll all viewports != vp */
738 cvlist
= l
->l_cvlist
;
739 cvlnext
= cv
->c_lnext
;
742 LScrollV(l
, 1, top
, bot
, bce
);
746 LInsChar(l
, c
, 0, bot
, 0);
748 LPutChar(l
, c
, 0, bot
);
750 l
->l_cvlist
= cvlist
;
751 cv
->c_lnext
= cvlnext
;
755 /* add vp back to cvlist */
757 top2
= top
+ vp
->v_yoff
;
758 bot2
= bot
+ vp
->v_yoff
;
761 WrapChar(RECODE_MCHAR(c
), vp
->v_xoff
+ l
->l_width
, bot2
, vp
->v_xoff
, top2
, vp
->v_xoff
+ l
->l_width
- 1, bot2
, ins
);
769 LCursorVisibility(l
, vis
)
774 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
776 display
= cv
->c_display
;
781 CursorVisibility(vis
);
791 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
793 display
= cv
->c_display
;
806 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
808 display
= cv
->c_display
;
818 LCursorkeysMode(l
, on
)
823 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
825 display
= cv
->c_display
;
840 for (cv
= l
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
842 display
= cv
->c_display
;
856 LClearArea(l
, 0, 0, l
->l_width
- 1, l
->l_height
- 1, 0, uself
);
860 LRefreshAll(l
, isblank
)
864 struct layer
*oldflayer
;
867 debug1("LRefreshAll isblank=%d\n", isblank
);
871 LClearArea(l
, 0, 0, l
->l_width
- 1, l
->l_height
- 1, 0, 0);
872 /* signal full refresh */
873 LayRedisplayLine(-1, -1, -1, 1);
874 for (y
= 0; y
< l
->l_height
; y
++)
875 LayRedisplayLine(y
, 0, l
->l_width
- 1, 1);
881 #if defined(USEVARARGS) && defined(__STDC__)
882 LMsg(int err
, char *fmt
, VA_DOTS
)
884 LMsg(err
, fmt
, VA_DOTS
)
891 char buf
[MAXPATHLEN
*2];
897 (void)vsnprintf(p
, sizeof(buf
) - 100, fmt
, VA_ARGS(ap
));
904 strncpy(p
, strerror(err
), buf
+ sizeof(buf
) - p
- 1);
905 buf
[sizeof(buf
) - 1] = 0;
907 debug2("LMsg('%s') (%#x);\n", buf
, (unsigned int)flayer
);
908 for (display
= displays
; display
; display
= display
->d_next
)
910 for (cv
= D_cvlist
; cv
; cv
= cv
->c_next
)
911 if (cv
->c_layer
== flayer
)
920 /*******************************************************************/
921 /*******************************************************************/
924 * Layer creation / removal
931 struct canvas
*cv
, *ncv
;
932 struct layer
*l
, *oldflayer
;
935 debug1("KillLayerChain %#x\n", lay
);
936 for (l
= lay
; l
; l
= l
->l_next
)
938 if (l
->l_layfn
== &WinLf
|| l
->l_layfn
== &BlankLf
)
940 debug1("- killing %#x\n", l
);
943 for (cv
= l
->l_cvlist
; cv
; cv
= ncv
)
959 InitOverlayPage(datasize
, lf
, block
)
965 struct layer
*newlay
;
966 struct canvas
*cv
, *cvp
, **cvpp
;
972 if (display
&& D_forecv
->c_layer
== flayer
)
973 cv
= D_forecv
; /* work only on this cv! */
975 if ((newlay
= (struct layer
*)calloc(1, sizeof(struct layer
))) == 0)
977 Msg(0, "No memory for layer struct");
980 debug2("Entering new layer on top of %#x: %#x\n", (unsigned int)flayer
, newlay
);
984 if ((data
= calloc(1, datasize
)) == 0)
986 free((char *)newlay
);
987 Msg(0, "No memory for layer data");
992 p
= Layer2Window(flayer
);
994 if (p
&& (p
->w_savelayer
== flayer
|| (block
&& flayer
->l_next
== 0)))
996 if (p
->w_savelayer
&& p
->w_savelayer
!= flayer
&& p
->w_savelayer
->l_cvlist
== 0)
997 KillLayerChain(p
->w_savelayer
);
998 p
->w_savelayer
= newlay
;
1001 if (cv
&& flayer
->l_next
== 0 && !block
)
1003 struct display
*olddisplay
= display
;
1004 display
= cv
->c_display
;
1006 display
= olddisplay
;
1008 /* new branch -> just get canvas vps */
1009 for (cvpp
= &flayer
->l_cvlist
; (cvp
= *cvpp
); cvpp
= &cvp
->c_lnext
)
1013 *cvpp
= cv
->c_lnext
;
1014 newlay
->l_cvlist
= cv
;
1016 cv
->c_layer
= newlay
;
1020 LAY_DISPLAYS(flayer
, RemoveStatus());
1022 debug("layer is blocking\n");
1023 if (block
&& flayer
->l_layfn
== &WinLf
)
1025 debug("...and is first, so window gets blocked\n");
1026 ASSERT(p
->w_blocked
== 0);
1028 newlay
->l_blocking
= 1;
1030 /* change all canvases */
1031 newlay
->l_cvlist
= flayer
->l_cvlist
;
1032 for (cvp
= newlay
->l_cvlist
; cvp
; cvp
= cvp
->c_lnext
)
1033 cvp
->c_layer
= newlay
;
1034 flayer
->l_cvlist
= 0;
1036 newlay
->l_width
= flayer
->l_width
;
1037 newlay
->l_height
= flayer
->l_height
;
1038 newlay
->l_encoding
= 0;
1039 newlay
->l_layfn
= lf
;
1040 newlay
->l_data
= data
;
1041 newlay
->l_next
= flayer
;
1042 newlay
->l_bottom
= flayer
->l_bottom
;
1048 extern struct layout
*layouts
;
1053 struct layer
*oldlay
;
1055 int doredisplay
= 0;
1056 struct canvas
*cv
, *ocv
;
1060 debug1("Exiting layer %#x\n", (unsigned int)flayer
);
1063 free(oldlay
->l_data
);
1065 p
= Layer2Window(flayer
);
1067 flayer
= oldlay
->l_next
;
1068 if (flayer
->l_layfn
== &WinLf
)
1070 if (oldlay
->l_blocking
)
1072 ASSERT(p
->w_blocked
> 0);
1074 debug1("layer was blocking, -> w_blocked now %d\n", p
->w_blocked
);
1076 /* don't warp dead layers: check cvlist */
1077 if (p
->w_blocked
&& p
->w_savelayer
&& p
->w_savelayer
!= flayer
&& oldlay
->l_cvlist
)
1079 debug("warping to top of blocking chain!\n");
1080 /* warp ourself into savelayer */
1081 flayer
= p
->w_savelayer
;
1085 if (p
&& p
->w_savelayer
== oldlay
)
1086 p
->w_savelayer
= flayer
;
1088 if (p
&& oldlay
== p
->w_paster
.pa_pastelayer
)
1089 p
->w_paster
.pa_pastelayer
= 0;
1092 for (lay
= layouts
; lay
; lay
= lay
->lay_next
)
1093 for (cv
= lay
->lay_cvlist
; cv
; cv
= cv
->c_next
)
1094 if (cv
->c_layer
== oldlay
)
1095 cv
->c_layer
= flayer
;
1097 /* add all canvases back into next layer's canvas list */
1098 for (ocv
= 0, cv
= oldlay
->l_cvlist
; cv
; cv
= cv
->c_lnext
)
1100 cv
->c_layer
= flayer
;
1105 cv
= flayer
->l_cvlist
;
1107 flayer
->l_cvlist
= oldlay
->l_cvlist
;
1108 /* redisplay only the warped cvs */
1110 LRefreshAll(flayer
, 0);
1113 oldlay
->l_cvlist
= 0;
1114 free((char *)oldlay
);