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
5 *
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)
9 * any later version.
10 *
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.
15 *
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
20 *
21 ****************************************************************
22 */
23
24#include <sys/types.h>
25
26#include "config.h"
27#include "screen.h"
28#include "mark.h"
29#include "extern.h"
30#include "braille.h"
31
32extern struct display *display, *displays;
33
34extern struct mline mline_blank, mline_null;
35extern struct mchar mchar_blank, mchar_null;
36
37extern struct layer *flayer;	/* sigh */
38extern struct LayFuncs WinLf;
39extern struct LayFuncs BlankLf;
40
41
42static struct mline *mloff __P((struct mline *, int));
43
44/*
45 * Layer subsystem.
46 *
47 * ...here is all the clipping code... beware!
48 *
49 * XXX: add some speedup code!
50 *
51 */
52
53static struct mline *
54mloff(ml, off)
55struct mline *ml;
56int off;
57{
58  static struct mline mml;
59
60  if (ml == 0)
61    return 0;
62  mml.image = ml->image + off;
63  mml.attr  = ml->attr  + off;
64#ifdef FONT
65  mml.font  = ml->font  + off;
66#endif
67#ifdef COLOR
68  mml.color = ml->color + off;
69# ifdef COLORS256
70  mml.colorx = ml->colorx + off;
71# endif
72#endif
73  return &mml;
74}
75
76#ifdef UTF8
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))
79#else
80# define RECODE_MCHAR(mc) (mc)
81# define RECODE_MLINE(ml) (ml)
82#endif
83
84
85void
86LGotoPos(l, x, y)
87struct layer *l;
88int x, y;
89{
90  struct canvas *cv;
91  struct viewport *vp;
92  int x2, y2;
93
94#ifdef HAVE_BRAILLE
95  if (bd.bd_refreshing)
96    return;
97#endif
98  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
99    {
100      display = cv->c_display;
101      if (D_blocked)
102	continue;
103      if (cv != D_forecv)
104	continue;
105      x2 = x + cv->c_xoff;
106      y2 = y + cv->c_yoff;
107      debug2("---LGotoPos %d %d\n", x2, y2);
108      if (x2 < cv->c_xs)
109	x2 = cv->c_xs;
110      if (y2 < cv->c_ys)
111	y2 = cv->c_ys;
112      if (x2 > cv->c_xe)
113	x2 = cv->c_xe;
114      if (y2 > cv->c_ye)
115	y2 = cv->c_ye;
116      for (vp = cv->c_vplist; vp; vp = vp->v_next)
117	{
118	  if (x2 < vp->v_xs || x2 > vp->v_xe)
119	    continue;
120	  if (y2 < vp->v_ys || y2 > vp->v_ye)
121	    continue;
122	  GotoPos(x2, y2);
123	  break;
124	}
125    }
126}
127
128void
129LScrollH(l, n, y, xs, xe, bce, ol)
130struct layer *l;
131int n, y, xs, xe;
132int bce;
133struct mline *ol;
134{
135  struct canvas *cv;
136  struct viewport *vp;
137  int y2, xs2, xe2;
138
139  if (n == 0)
140    return;
141  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
142    for (vp = cv->c_vplist; vp; vp = vp->v_next)
143      {
144	y2 = y + vp->v_yoff;
145	if (y2 < vp->v_ys || y2 > vp->v_ye)
146	  continue;
147	xs2 = xs + vp->v_xoff;
148	xe2 = xe + vp->v_xoff;
149	if (xs2 < vp->v_xs)
150	  xs2 = vp->v_xs;
151	if (xe2 > vp->v_xe)
152	  xe2 = vp->v_xe;
153	if (xs2 > xe2)
154	  continue;
155	display = cv->c_display;
156	if (D_blocked)
157	  continue;
158	ScrollH(y2, xs2, xe2, n, bce, ol ? mloff(ol, -vp->v_xoff) : 0);
159	if (xe2 - xs2 == xe - xs)
160	  continue;
161	if (n > 0)
162	  {
163	    xs2 = xe2 + 1 - n;
164	    xe2 = xe + vp->v_xoff - n;
165	  }
166	else
167	  {
168	    xe2 = xs2 - 1 - n;
169	    xs2 = xs + vp->v_xoff - n;
170	  }
171	if (xs2 < vp->v_xs)
172	  xs2 = vp->v_xs;
173	if (xe2 > vp->v_xe)
174	  xe2 = vp->v_xe;
175	if (xs2 <= xe2)
176	  RefreshArea(xs2, y2, xe2, y2, 1);
177      }
178}
179
180void
181LScrollV(l, n, ys, ye, bce)
182struct layer *l;
183int n;
184int ys, ye;
185int bce;
186{
187  struct canvas *cv;
188  struct viewport *vp;
189  int ys2, ye2, xs2, xe2;
190  if (n == 0)
191    return;
192  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
193    for (vp = cv->c_vplist; vp; vp = vp->v_next)
194      {
195	xs2 = vp->v_xoff;
196	xe2 = l->l_width - 1 + vp->v_xoff;
197	ys2 = ys + vp->v_yoff;
198	ye2 = ye + vp->v_yoff;
199	if (xs2 < vp->v_xs)
200	  xs2 = vp->v_xs;
201	if (xe2 > vp->v_xe)
202	  xe2 = vp->v_xe;
203	if (ys2 < vp->v_ys)
204	  ys2 = vp->v_ys;
205	if (ye2 > vp->v_ye)
206	  ye2 = vp->v_ye;
207	if (ys2 > ye2 || xs2 > xe2)
208	  continue;
209	display = cv->c_display;
210	if (D_blocked)
211	  continue;
212#if 0
213	ScrollV(xs2, ys2, xe2, ye2, n, bce);
214#else
215	ScrollV(vp->v_xs, ys2, vp->v_xe, ye2, n, bce);
216#endif
217	debug2("LScrollV: %d %d", ys, ye);
218	debug2(" -> %d %d\n", ys2, ye2);
219	if (ye2 - ys2 == ye - ys)
220	  continue;
221	if (n > 0)
222	  {
223	    ys2 = ye2 + 1 - n;
224	    ye2 = ye + vp->v_yoff - n;
225	  }
226	else
227	  {
228	    ye2 = ys2 - 1 - n;
229	    ys2 = ys + vp->v_yoff - n;
230	  }
231	debug2("LScrollV: - %d %d\n", ys2, ye2);
232	if (ys2 < vp->v_ys)
233	  ys2 = vp->v_ys;
234	if (ye2 > vp->v_ye)
235	  ye2 = vp->v_ye;
236	debug2("LScrollV: - %d %d\n", ys2, ye2);
237	if (ys2 <= ye2)
238	  RefreshArea(xs2, ys2, xe2, ye2, 1);
239      }
240}
241
242void
243LInsChar(l, c, x, y, ol)
244struct layer *l;
245struct mchar *c;
246int x, y;
247struct mline *ol;
248{
249  struct canvas *cv;
250  struct viewport *vp;
251  int xs2, xe2, y2, f;
252  struct mchar *c2, cc;
253  struct mline *rol;
254
255  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
256    for (vp = cv->c_vplist; vp; vp = vp->v_next)
257      {
258	y2 = y + vp->v_yoff;
259	if (y2 < vp->v_ys || y2 > vp->v_ye)
260	  continue;
261	xs2 = x + vp->v_xoff;
262	xe2 = l->l_width - 1 + vp->v_xoff;
263	c2 = c;
264	f = 0;
265	if (xs2 < vp->v_xs)
266	  {
267	    xs2 = vp->v_xs;
268	    c2 = &mchar_blank;
269	    if (ol)
270	      {
271		int i;
272		i = xs2 - vp->v_xoff - 1;
273		if (i >= 0 && i < l->l_width)
274		  {
275		    copy_mline2mchar(&cc, ol, i);
276		    c2 = &cc;
277		  }
278	      }
279	    else
280	      f = 1;
281	  }
282	if (xe2 > vp->v_xe)
283	  xe2 = vp->v_xe;
284	if (xs2 > xe2)
285	  continue;
286	display = cv->c_display;
287	if (D_blocked)
288	  continue;
289        rol = RECODE_MLINE(ol);
290	InsChar(RECODE_MCHAR(c2), xs2, xe2, y2, mloff(rol, -vp->v_xoff));
291	if (f)
292	  RefreshArea(xs2, y2, xs2, y2, 1);
293      }
294}
295
296void
297LPutChar(l, c, x, y)
298struct layer *l;
299struct mchar *c;
300int x, y;
301{
302  struct canvas *cv;
303  struct viewport *vp;
304  int x2, y2;
305#ifdef HAVE_BRAILLE
306  if (bd.bd_refreshing)
307    {
308      BPutChar(l, c, x, y);
309      return;
310    }
311#endif
312  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
313    {
314      display = cv->c_display;
315      if (D_blocked)
316	continue;
317      for (vp = cv->c_vplist; vp; vp = vp->v_next)
318	{
319	  y2 = y + vp->v_yoff;
320	  if (y2 < vp->v_ys || y2 > vp->v_ye)
321	    continue;
322	  x2 = x + vp->v_xoff;
323	  if (x2 < vp->v_xs || x2 > vp->v_xe)
324	    continue;
325	  PutChar(RECODE_MCHAR(c), x2, y2);
326	  break;
327	}
328    }
329}
330
331void
332LPutStr(l, s, n, r, x, y)
333struct layer *l;
334char *s;
335int n;
336struct mchar *r;
337int x, y;
338{
339  struct canvas *cv;
340  struct viewport *vp;
341  char *s2;
342  int xs2, xe2, y2;
343
344  if (x + n > l->l_width)
345    n = l->l_width - x;
346#ifdef HAVE_BRAILLE
347  if (bd.bd_refreshing)
348    {
349      BPutStr(l, s, n, r, x, y);
350      return;
351    }
352#endif
353  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
354    for (vp = cv->c_vplist; vp; vp = vp->v_next)
355      {
356	y2 = y + vp->v_yoff;
357	if (y2 < vp->v_ys || y2 > vp->v_ye)
358	  continue;
359	xs2 = x + vp->v_xoff;
360	xe2 = xs2 + n - 1;
361	if (xs2 < vp->v_xs)
362	  xs2 = vp->v_xs;
363	if (xe2 > vp->v_xe)
364	  xe2 = vp->v_xe;
365	if (xs2 > xe2)
366	  continue;
367	display = cv->c_display;
368        if (D_blocked)
369	  continue;
370	GotoPos(xs2, y2);
371	SetRendition(r);
372	s2 = s + xs2 - x - vp->v_xoff;
373#ifdef UTF8
374	if (D_encoding == UTF8 && l->l_encoding != UTF8 && (r->font || l->l_encoding))
375	  {
376	    struct mchar mc;
377	    mc = *r;
378	    while (xs2 <= xe2)
379	      {
380		mc.image = *s2++;
381	        PutChar(RECODE_MCHAR(&mc), xs2++, y2);
382	      }
383	    continue;
384	  }
385#endif
386	while (xs2++ <= xe2)
387	  PUTCHARLP(*s2++);
388      }
389}
390
391void
392LPutWinMsg(l, s, n, r, x, y)
393struct layer *l;
394char *s;
395int n;
396struct mchar *r;
397int x, y;
398{
399  struct canvas *cv;
400  struct viewport *vp;
401  char *s2;
402  int xs2, xe2, y2, len, len2;
403  struct mchar or;
404
405  if (x + n > l->l_width)
406    n = l->l_width - x;
407#ifdef HAVE_BRAILLE
408  if (bd.bd_refreshing)
409    {
410      BPutStr(l, s, n, r, x, y);
411      return;
412    }
413#endif
414  len = strlen(s);
415  if (len > n)
416    len = n;
417  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
418    for (vp = cv->c_vplist; vp; vp = vp->v_next)
419      {
420	y2 = y + vp->v_yoff;
421	if (y2 < vp->v_ys || y2 > vp->v_ye)
422	  continue;
423	xs2 = x + vp->v_xoff;
424	xe2 = xs2 + n - 1;
425	if (xs2 < vp->v_xs)
426	  xs2 = vp->v_xs;
427	if (xe2 > vp->v_xe)
428	  xe2 = vp->v_xe;
429	if (xs2 > xe2)
430	  continue;
431	display = cv->c_display;
432        if (D_blocked)
433	  continue;
434	GotoPos(xs2, y2);
435	SetRendition(r);
436	len2 = xe2 - (x + vp->v_xoff) + 1;
437	if (len2 > len)
438	  len2 = len;
439	if (!PutWinMsg(s, xs2 - x - vp->v_xoff, len2))
440	  {
441	    s2 = s + xs2 - x - vp->v_xoff;
442	    while (len2-- > 0)
443	      {
444	        PUTCHARLP(*s2++);
445		xs2++;
446	      }
447	  }
448        else
449	  xs2 = x + vp->v_xoff + len2;
450	if (xs2 < vp->v_xs)
451	  xs2 = vp->v_xs;
452	or = D_rend;
453	GotoPos(xs2, y2);
454	SetRendition(&or);
455	while (xs2++ <= xe2)
456	  PUTCHARLP(' ');
457      }
458}
459
460void
461LClearLine(l, y, xs, xe, bce, ol)
462struct layer *l;
463#ifdef __APPLE__
464int y;
465#endif
466int xs, xe, bce;
467struct mline *ol;
468{
469  struct canvas *cv;
470  struct viewport *vp;
471  int y2, xs2, xe2;
472
473  /* check for magic margin condition */
474  if (xs >= l->l_width)
475    xs = l->l_width - 1;
476  if (xe >= l->l_width)
477    xe = l->l_width - 1;
478  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
479    for (vp = cv->c_vplist; vp; vp = vp->v_next)
480      {
481	xs2 = xs + vp->v_xoff;
482	xe2 = xe + vp->v_xoff;
483	y2  = y + vp->v_yoff;
484	if (y2 < vp->v_ys || y2 > vp->v_ye)
485	  continue;
486	if (xs2 < vp->v_xs)
487	  xs2 = vp->v_xs;
488	if (xe2 > vp->v_xe)
489	  xe2 = vp->v_xe;
490	if (xs2 > xe2)
491	  continue;
492	display = cv->c_display;
493        if (D_blocked)
494	  continue;
495	ClearLine(ol ? mloff(RECODE_MLINE(ol), -vp->v_xoff) : (struct mline *)0, y2, xs2, xe2, bce);
496      }
497}
498
499void
500LClearArea(l, xs, ys, xe, ye, bce, uself)
501struct layer *l;
502int xs, ys, xe, ye;
503int bce;
504int uself;
505{
506  struct canvas *cv;
507  struct viewport *vp;
508  int xs2, ys2, xe2, ye2;
509#ifdef HAVE_BRAILLE
510  if (bd.bd_refreshing)
511    return;
512#endif
513  /* check for magic margin condition */
514  if (xs >= l->l_width)
515    xs = l->l_width - 1;
516  if (xe >= l->l_width)
517    xe = l->l_width - 1;
518  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
519    {
520      display = cv->c_display;
521      if (D_blocked)
522	continue;
523      for (vp = cv->c_vplist; vp; vp = vp->v_next)
524	{
525	  xs2 = xs + vp->v_xoff;
526	  xe2 = xe + vp->v_xoff;
527	  ys2 = ys + vp->v_yoff;
528	  ye2 = ye + vp->v_yoff;
529	  if (xs2 < vp->v_xs)
530	    xs2 = vp->v_xs;
531	  if (xe2 > vp->v_xe)
532	    xe2 = vp->v_xe;
533	  if (xs2 > vp->v_xe)
534	    ys2++;
535	  if (xe2 < vp->v_xs)
536	    ye2--;
537	  if (ys2 < vp->v_ys)
538	    ys2 = vp->v_ys;
539	  if (ye2 > vp->v_ye)
540	    ye2 = vp->v_ye;
541	  if (ys2 > ye2)
542	    continue;
543#if 0
544	  xcs = vp->v_xoff;
545	  xce = l->l_width - 1 + vp->v_xoff;
546	  if (xcs < vp->v_xs)
547	    xcs = vp->v_xs;
548	  if (xce > vp->v_xe)
549	    xce = vp->v_xe;
550	  if (xcs > xce)
551	    continue;
552	  if (ys2 != ys + vp->v_yoff)
553	    xs2 = xcs;
554	  if (ye2 != ye + vp->v_yoff)
555	    xe2 = xce;
556	  display = cv->c_display;
557	  ClearArea(xs2, ys2, xcs, xce, xe2, ye2, bce, uself);
558#else
559	  if (xs == 0 || ys2 != ys + vp->v_yoff)
560	    xs2 = vp->v_xs;
561	  if (xe == l->l_width - 1 || ye2 != ye + vp->v_yoff)
562	    xe2 = vp->v_xe;
563	  display = cv->c_display;
564	  ClearArea(xs2, ys2, vp->v_xs, vp->v_xe, xe2, ye2, bce, uself);
565#endif
566	}
567    }
568}
569
570void
571LCDisplayLine(l, ml, y, xs, xe, isblank)
572struct layer *l;
573struct mline *ml;
574int y, xs, xe;
575int isblank;
576{
577  struct canvas *cv;
578  struct viewport *vp;
579  int xs2, xe2, y2;
580#ifdef HAVE_BRAILLE
581  if (bd.bd_refreshing)
582    {
583      BCDisplayLine(l, ml, y, xs, xe, isblank);
584      return;
585    }
586#endif
587  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
588    {
589      display = cv->c_display;
590      if (D_blocked)
591	continue;
592      for (vp = cv->c_vplist; vp; vp = vp->v_next)
593	{
594	  xs2 = xs + vp->v_xoff;
595	  xe2 = xe + vp->v_xoff;
596	  y2  = y + vp->v_yoff;
597	  if (y2 < vp->v_ys || y2 > vp->v_ye)
598	    continue;
599	  if (xs2 < vp->v_xs)
600	    xs2 = vp->v_xs;
601	  if (xe2 > vp->v_xe)
602	    xe2 = vp->v_xe;
603	  if (xs2 > xe2)
604	    continue;
605	  display = cv->c_display;
606	  debug3("LCDisplayLine: DisplayLine %d, %d-%d", y2, xs2, xe2);
607	  debug1("  mloff = %d\n", -vp->v_xoff);
608	  DisplayLine(isblank ? &mline_blank : &mline_null, mloff(RECODE_MLINE(ml), -vp->v_xoff), y2, xs2, xe2);
609	}
610    }
611}
612
613void
614LCDisplayLineWrap(l, ml, y, from, to, isblank)
615struct layer *l;
616struct mline *ml;
617int y, from, to;
618int isblank;
619{
620  struct mchar nc;
621  copy_mline2mchar(&nc, ml, 0);
622#ifdef DW_CHARS
623  if (dw_left(ml, 0, l->l_encoding))
624    {
625      nc.mbcs = ml->image[1];
626      from++;
627    }
628#endif
629  LWrapChar(l, &nc, y - 1, -1, -1, 0);
630  from++;
631  if (from <= to)
632    LCDisplayLine(l, ml, y, from, to, isblank);
633}
634
635void
636LSetRendition(l, r)
637struct layer *l;
638struct mchar *r;
639{
640  struct canvas *cv;
641
642  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
643    {
644      display = cv->c_display;
645      if (D_blocked)
646	continue;
647      SetRendition(r);
648    }
649}
650
651void
652LWrapChar(l, c, y, top, bot, ins)
653struct layer *l;
654struct mchar *c;
655int y, top, bot;
656int ins;
657{
658  struct canvas *cv, *cvlist, *cvlnext;
659  struct viewport *vp, *evp, **vpp;
660  int yy, y2, yy2, top2, bot2;
661  int bce;
662
663#ifdef COLOR
664  bce = rend_getbg(c);
665#else
666  bce = 0;
667#endif
668  if (y != bot)
669    {
670      /* simple case: no scrolling */
671
672      /* cursor after wrapping */
673      yy = y == l->l_height - 1 ? y : y + 1;
674
675      for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
676	{
677	  y2 = 0;       /* gcc -Wall */
678	  display = cv->c_display;
679	  if (D_blocked)
680	    continue;
681	  /* find the viewport of the wrapped character */
682	  for (vp = cv->c_vplist; vp; vp = vp->v_next)
683	    {
684	      y2 =  y + vp->v_yoff;
685	      yy2 = yy + vp->v_yoff;
686	      if (yy2 >= vp->v_ys && yy2 <= vp->v_ye && vp->v_xoff >= vp->v_xs && vp->v_xoff <= vp->v_xe)
687		break;
688	    }
689	  if (vp == 0)
690	    continue;	/* nothing to do, character not visible */
691	  /* find the viewport of the character at the end of the line*/
692	  for (evp = cv->c_vplist; evp; evp = evp->v_next)
693	    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)
694	      break;	/* gotcha! */
695	  if (evp == 0 || (ins && vp->v_xoff + l->l_width - 1 > vp->v_ye))
696	    {
697	      /* no wrapping possible */
698	      debug("LWrap: can't wrap!\n");
699	      cvlist = l->l_cvlist;
700	      cvlnext = cv->c_lnext;
701	      l->l_cvlist = cv;
702	      cv->c_lnext = 0;
703	      if (ins)
704		LInsChar(l, c, 0, yy, 0);
705	      else
706	        LPutChar(l, c, 0, yy);
707	      l->l_cvlist = cvlist;
708	      cv->c_lnext = cvlnext;
709	    }
710	  else
711	    {
712	      WrapChar(RECODE_MCHAR(c), vp->v_xoff + l->l_width, y2, vp->v_xoff, -1, vp->v_xoff + l->l_width - 1, -1, ins);
713	    }
714	}
715    }
716  else
717    {
718      /* hard case: scroll up*/
719
720      for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
721	{
722	  display = cv->c_display;
723	  if (D_blocked)
724	    continue;
725	  /* search for wrap viewport */
726	  for (vpp = &cv->c_vplist; (vp = *vpp); vpp = &vp->v_next)
727	    {
728	      yy2 = bot + vp->v_yoff;
729	      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)
730		break;
731	    }
732
733	  if (vp)
734	    {
735	      /* great, can use Wrap on the vp */
736	      /* temporarily remove vp from cvlist */
737	      *vpp = vp->v_next;
738	    }
739	  if (cv->c_vplist)
740	    {
741	      /* scroll all viewports != vp */
742	      cvlist = l->l_cvlist;
743	      cvlnext = cv->c_lnext;
744	      l->l_cvlist = cv;
745	      cv->c_lnext = 0;
746	      LScrollV(l, 1, top, bot, bce);
747	      if (!vp)
748		{
749		  if (ins)
750		    LInsChar(l, c, 0, bot, 0);
751		  else
752		    LPutChar(l, c, 0, bot);
753		}
754	      l->l_cvlist = cvlist;
755	      cv->c_lnext = cvlnext;
756	    }
757	  if (vp)
758	    {
759	      /* add vp back to cvlist */
760	      *vpp = vp;
761	      top2 = top + vp->v_yoff;
762	      bot2 = bot + vp->v_yoff;
763	      if (top2 < vp->v_ys)
764		top2 = vp->v_ys;
765	      WrapChar(RECODE_MCHAR(c), vp->v_xoff + l->l_width, bot2, vp->v_xoff, top2, vp->v_xoff + l->l_width - 1, bot2, ins);
766	    }
767	}
768    }
769}
770
771
772void
773LCursorVisibility(l, vis)
774struct layer *l;
775int vis;
776{
777  struct canvas *cv;
778  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
779    {
780      display = cv->c_display;
781      if (D_blocked)
782	continue;
783      if (cv != D_forecv)
784	continue;
785      CursorVisibility(vis);
786    }
787}
788
789void
790LSetFlow(l, flow)
791struct layer *l;
792int flow;
793{
794  struct canvas *cv;
795  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
796    {
797      display = cv->c_display;
798      if (cv != D_forecv)
799	continue;
800      SetFlow(flow);
801    }
802}
803
804void
805LKeypadMode(l, on)
806struct layer *l;
807int on;
808{
809  struct canvas *cv;
810  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
811    {
812      display = cv->c_display;
813      if (D_blocked)
814	continue;
815      if (cv != D_forecv)
816	continue;
817      KeypadMode(on);
818    }
819}
820
821void
822LCursorkeysMode(l, on)
823struct layer *l;
824int on;
825{
826  struct canvas *cv;
827  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
828    {
829      display = cv->c_display;
830      if (D_blocked)
831	continue;
832      if (cv != D_forecv)
833	continue;
834      CursorkeysMode(on);
835    }
836}
837
838void
839LMouseMode(l, on)
840struct layer *l;
841int on;
842{
843  struct canvas *cv;
844  for (cv = l->l_cvlist; cv; cv = cv->c_lnext)
845    {
846      display = cv->c_display;
847      if (D_blocked)
848	continue;
849      if (cv != D_forecv)
850	continue;
851      MouseMode(on);
852    }
853}
854
855
856/*******************************************************************/
857
858void
859LClearAll(l, uself)
860struct layer *l;
861int uself;
862{
863  LClearArea(l, 0, 0, l->l_width - 1, l->l_height - 1, 0, uself);
864}
865
866void
867LRefreshAll(l, isblank)
868struct layer *l;
869int isblank;
870{
871  struct layer *oldflayer;
872  int y;
873
874  debug1("LRefreshAll isblank=%d\n", isblank);
875  oldflayer = flayer;
876  flayer = l;
877  if (!isblank)
878    LClearArea(l, 0, 0, l->l_width - 1, l->l_height - 1, 0, 0);
879  /* signal full refresh */
880  LayRedisplayLine(-1, -1, -1, 1);
881  for (y = 0; y < l->l_height; y++)
882    LayRedisplayLine(y, 0, l->l_width - 1, 1);
883  flayer = oldflayer;
884}
885
886
887void
888KillLayerChain(lay)
889struct layer *lay;
890{
891  struct canvas *cv, *ncv;
892  struct layer *l, *oldflayer;
893
894  oldflayer = flayer;
895  debug1("KillLayerChain %#x\n", lay);
896  for (l = lay; l; l = l->l_next)
897    {
898      if (l->l_layfn == &WinLf || l->l_layfn == &BlankLf)
899	break;
900      debug1("- killing %#x\n", l);
901      if (oldflayer == l)
902	oldflayer = 0;
903      for (cv = l->l_cvlist; cv; cv = ncv)
904	{
905	  ncv = cv->c_lnext;
906	  cv->c_layer = 0;
907	  cv->c_lnext = 0;
908	}
909    }
910  flayer = lay;
911  while (flayer != l)
912    ExitOverlayPage();
913  flayer = oldflayer;
914}
915
916
917/*******************************************************************/
918/*******************************************************************/
919
920/*
921 *  Layer creation / removal
922 */
923
924int
925InitOverlayPage(datasize, lf, block)
926int datasize;
927struct LayFuncs *lf;
928int block;
929{
930  char *data;
931  struct layer *newlay;
932  struct canvas *cv, *cvp, **cvpp;
933  struct win *p;
934
935  ASSERT(flayer);
936
937  cv = 0;
938  if (display && D_forecv->c_layer == flayer)
939    cv = D_forecv;	/* work only on this cv! */
940
941  if ((newlay = (struct layer *)calloc(1, sizeof(struct layer))) == 0)
942    {
943      Msg(0, "No memory for layer struct");
944      return -1;
945    }
946  debug2("Entering new layer on top of %#x: %#x\n", (unsigned int)flayer, newlay);
947  data = 0;
948  if (datasize)
949    {
950      if ((data = malloc(datasize)) == 0)
951	{
952	  free((char *)newlay);
953	  Msg(0, "No memory for layer data");
954	  return -1;
955	}
956      bzero(data, datasize);
957    }
958
959  p = Layer2Window(flayer);
960
961  if (p && (p->w_savelayer == flayer || (block && flayer->l_next == 0)))
962    {
963      if (p->w_savelayer && p->w_savelayer != flayer && p->w_savelayer->l_cvlist == 0)
964	KillLayerChain(p->w_savelayer);
965      p->w_savelayer = newlay;
966    }
967
968  if (cv && flayer->l_next == 0 && !block)
969    {
970      struct display *olddisplay = display;
971      display = cv->c_display;
972      RemoveStatus();
973      display = olddisplay;
974
975      /* new branch -> just get canvas vps */
976      for (cvpp = &flayer->l_cvlist; (cvp = *cvpp); cvpp = &cvp->c_lnext)
977	if (cvp == cv)
978	  break;
979      ASSERT(cvp);
980      *cvpp = cv->c_lnext;
981      newlay->l_cvlist = cv;
982      cv->c_lnext = 0;
983      cv->c_layer = newlay;
984    }
985  else
986    {
987      LAY_DISPLAYS(flayer, RemoveStatus());
988      if (block)
989        debug("layer is blocking\n");
990      if (block && flayer->l_layfn == &WinLf)
991	{
992          debug("...and is first, so window gets blocked\n");
993	  ASSERT(p->w_blocked == 0);
994	  p->w_blocked++;
995	  newlay->l_blocking = 1;
996	}
997      /* change all canvases */
998      newlay->l_cvlist = flayer->l_cvlist;
999      for (cvp = newlay->l_cvlist; cvp; cvp = cvp->c_lnext)
1000	cvp->c_layer = newlay;
1001      flayer->l_cvlist = 0;
1002    }
1003  newlay->l_width = flayer->l_width;
1004  newlay->l_height = flayer->l_height;
1005  newlay->l_encoding = 0;
1006  newlay->l_layfn = lf;
1007  newlay->l_data = data;
1008  newlay->l_next = flayer;
1009  newlay->l_bottom = flayer->l_bottom;
1010  flayer = newlay;
1011  LayRestore();
1012  return 0;
1013}
1014
1015void
1016ExitOverlayPage()
1017{
1018  struct layer *oldlay;
1019  struct win *p;
1020  int doredisplay = 0;
1021  struct canvas *cv, *ocv;
1022
1023  ASSERT(flayer);
1024  debug1("Exiting layer %#x\n", (unsigned int)flayer);
1025  oldlay = flayer;
1026  if (oldlay->l_data)
1027    free(oldlay->l_data);
1028
1029  p = Layer2Window(flayer);
1030
1031  flayer = oldlay->l_next;
1032  if (flayer->l_layfn == &WinLf)
1033    {
1034      if (oldlay->l_blocking)
1035	{
1036	  ASSERT(p->w_blocked > 0);
1037	  p->w_blocked--;
1038          debug1("layer was blocking, -> w_blocked now %d\n", p->w_blocked);
1039	}
1040      /* don't warp dead layers: check cvlist */
1041      if (p->w_blocked && p->w_savelayer && p->w_savelayer != flayer && oldlay->l_cvlist)
1042	{
1043          debug("warping to top of blocking chain!\n");
1044	  /* warp ourself into savelayer */
1045	  flayer = p->w_savelayer;
1046	  doredisplay = 1;
1047	}
1048    }
1049  if (p && p->w_savelayer == oldlay)
1050    p->w_savelayer = flayer;
1051#ifdef COPY_PASTE
1052  if (p && oldlay == p->w_paster.pa_pastelayer)
1053    p->w_paster.pa_pastelayer = 0;
1054#endif
1055
1056  /* add all canvases back into next layer's canvas list */
1057  for (ocv = 0, cv = oldlay->l_cvlist; cv; cv = cv->c_lnext)
1058    {
1059      cv->c_layer = flayer;
1060      ocv = cv;
1061    }
1062  if (ocv)
1063    {
1064      cv = flayer->l_cvlist;
1065      ocv->c_lnext = 0;
1066      flayer->l_cvlist = oldlay->l_cvlist;
1067      /* redisplay only the warped cvs */
1068      if (doredisplay)
1069	LRefreshAll(flayer, 0);
1070      ocv->c_lnext = cv;
1071    }
1072  oldlay->l_cvlist = 0;
1073  free((char *)oldlay);
1074  LayRestore();
1075  LaySetCursor();
1076}
1077
1078void
1079/*VARARGS2*/
1080#if defined(USEVARARGS) && defined(__STDC__)
1081LMsg(int err, char *fmt, VA_DOTS)
1082#else
1083LMsg(err, fmt, VA_DOTS)
1084int err;
1085char *fmt;
1086VA_DECL
1087#endif
1088{
1089  VA_LIST(ap)
1090  char buf[MAXPATHLEN*2];
1091  char *p = buf;
1092  struct canvas *cv;
1093
1094  VA_START(ap, fmt);
1095  fmt = DoNLS(fmt);
1096  (void)vsnprintf(p, sizeof(buf) - 100, fmt, VA_ARGS(ap));
1097  VA_END(ap);
1098  if (err)
1099    {
1100      p += strlen(p);
1101      *p++ = ':';
1102      *p++ = ' ';
1103      strncpy(p, strerror(err), buf + sizeof(buf) - p - 1);
1104      buf[sizeof(buf) - 1] = 0;
1105    }
1106  debug2("LMsg('%s') (%#x);\n", buf, (unsigned int)flayer);
1107  for (display = displays; display; display = display->d_next)
1108    {
1109      for (cv = D_cvlist; cv; cv = cv->c_next)
1110	if (cv->c_layer == flayer)
1111	  break;
1112      if (cv == 0)
1113	continue;
1114      MakeStatus(buf);
1115    }
1116}
1117
1118