/* Copyright (c) 2008-2017 * Juergen Weigert * Michael Schroeder * Micah Cowan * Sadrul Habib Chowdhury * * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007 * Juergen Weigert * Michael Schroeder * * Copyright (c) 1987 Oliver Laumann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file COPYING); if not, see * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA * **************************************************************** */ #include #include "config.h" #include "screen.h" #include "mark.h" #include "extern.h" #include "braille.h" extern struct display *display, *displays; extern struct mline mline_blank, mline_null; extern struct mchar mchar_blank, mchar_null; extern struct layer *flayer; /* sigh */ extern struct LayFuncs WinLf; extern struct LayFuncs BlankLf; static struct mline *mloff __P((struct mline *, int)); /* * Layer subsystem. * * ...here is all the clipping code... beware! * * XXX: add some speedup code! * */ static struct mline *mloff(struct mline *ml, int off) { static struct mline mml; if (ml == 0) return 0; mml.image = ml->image + off; mml.attr = ml->attr + off; #ifdef FONT mml.font = ml->font + off; mml.fontx = ml->fontx + off; #endif #ifdef COLOR mml.color = ml->color + off; # ifdef COLORS256 mml.colorx = ml->colorx + off; # endif #endif return &mml; } #ifdef UTF8 # define RECODE_MCHAR(mc) ((l->l_encoding == UTF8) != (D_encoding == UTF8) ? recode_mchar(mc, l->l_encoding, D_encoding) : (mc)) # define RECODE_MLINE(ml) ((l->l_encoding == UTF8) != (D_encoding == UTF8) ? recode_mline(ml, l->l_width, l->l_encoding, D_encoding) : (ml)) #else # define RECODE_MCHAR(mc) (mc) # define RECODE_MLINE(ml) (ml) #endif #define FOR_EACH_UNPAUSED_CANVAS(l, fn) for (cv = (l)->l_cvlist; cv; cv = cv->c_lnext) \ { \ if ((l)->l_pause.d && cv->c_slorient) \ continue; \ fn \ } void LGotoPos(struct layer *l, int x, int y) { struct canvas *cv; struct viewport *vp; int x2, y2; if (l->l_pause.d) LayPauseUpdateRegion(l, x, x, y, y); #ifdef HAVE_BRAILLE if (bd.bd_refreshing) return; #endif FOR_EACH_UNPAUSED_CANVAS(l, { display = cv->c_display; if (D_blocked) continue; if (cv != D_forecv) continue; x2 = x + cv->c_xoff; y2 = y + cv->c_yoff; debug2("---LGotoPos %d %d\n", x2, y2); if (x2 < cv->c_xs) x2 = cv->c_xs; if (y2 < cv->c_ys) y2 = cv->c_ys; if (x2 > cv->c_xe) x2 = cv->c_xe; if (y2 > cv->c_ye) y2 = cv->c_ye; for (vp = cv->c_vplist; vp; vp = vp->v_next) { if (x2 < vp->v_xs || x2 > vp->v_xe) continue; if (y2 < vp->v_ys || y2 > vp->v_ye) continue; GotoPos(x2, y2); break; } } ); } void LScrollH(struct layer *l, int n, int y, int xs, int xe, int bce, struct mline *ol) { struct canvas *cv; struct viewport *vp; int y2, xs2, xe2; if (n == 0) return; if (l->l_pause.d) LayPauseUpdateRegion(l, xs, xe, y, y); FOR_EACH_UNPAUSED_CANVAS(l, for (vp = cv->c_vplist; vp; vp = vp->v_next) { y2 = y + vp->v_yoff; if (y2 < vp->v_ys || y2 > vp->v_ye) continue; xs2 = xs + vp->v_xoff; xe2 = xe + vp->v_xoff; if (xs2 < vp->v_xs) xs2 = vp->v_xs; if (xe2 > vp->v_xe) xe2 = vp->v_xe; if (xs2 > xe2) continue; display = cv->c_display; if (D_blocked) continue; ScrollH(y2, xs2, xe2, n, bce, ol ? mloff(ol, -vp->v_xoff) : 0); if (xe2 - xs2 == xe - xs) continue; if (n > 0) { xs2 = xe2 + 1 - n; xe2 = xe + vp->v_xoff - n; } else { xe2 = xs2 - 1 - n; xs2 = xs + vp->v_xoff - n; } if (xs2 < vp->v_xs) xs2 = vp->v_xs; if (xe2 > vp->v_xe) xe2 = vp->v_xe; if (xs2 <= xe2) RefreshArea(xs2, y2, xe2, y2, 1); } ); } void LScrollV(struct layer *l, int n, int ys, int ye, int bce) { struct canvas *cv; struct viewport *vp; int ys2, ye2, xs2, xe2; if (n == 0) return; if (l->l_pause.d) LayPauseUpdateRegion(l, 0, l->l_width - 1, ys, ye); FOR_EACH_UNPAUSED_CANVAS(l, for (vp = cv->c_vplist; vp; vp = vp->v_next) { xs2 = vp->v_xoff; xe2 = l->l_width - 1 + vp->v_xoff; ys2 = ys + vp->v_yoff; ye2 = ye + vp->v_yoff; if (xs2 < vp->v_xs) xs2 = vp->v_xs; if (xe2 > vp->v_xe) xe2 = vp->v_xe; if (ys2 < vp->v_ys) ys2 = vp->v_ys; if (ye2 > vp->v_ye) ye2 = vp->v_ye; if (ys2 > ye2 || xs2 > xe2) continue; display = cv->c_display; if (D_blocked) continue; #if 0 ScrollV(xs2, ys2, xe2, ye2, n, bce); #else ScrollV(vp->v_xs, ys2, vp->v_xe, ye2, n, bce); #endif debug2("LScrollV: %d %d", ys, ye); debug2(" -> %d %d\n", ys2, ye2); if (ye2 - ys2 == ye - ys) continue; if (n > 0) { ys2 = ye2 + 1 - n; ye2 = ye + vp->v_yoff - n; } else { ye2 = ys2 - 1 - n; ys2 = ys + vp->v_yoff - n; } debug2("LScrollV: - %d %d\n", ys2, ye2); if (ys2 < vp->v_ys) ys2 = vp->v_ys; if (ye2 > vp->v_ye) ye2 = vp->v_ye; debug2("LScrollV: - %d %d\n", ys2, ye2); if (ys2 <= ye2) RefreshArea(xs2, ys2, xe2, ye2, 1); } ); } void LInsChar(struct layer *l, struct mchar *c, int x, int y, struct mline *ol) { struct canvas *cv; struct viewport *vp; int xs2, xe2, y2, f; struct mchar *c2, cc; struct mline *rol; if (l->l_pause.d) LayPauseUpdateRegion(l, x, l->l_width - 1, y, y); FOR_EACH_UNPAUSED_CANVAS(l, for (vp = cv->c_vplist; vp; vp = vp->v_next) { y2 = y + vp->v_yoff; if (y2 < vp->v_ys || y2 > vp->v_ye) continue; xs2 = x + vp->v_xoff; xe2 = l->l_width - 1 + vp->v_xoff; c2 = c; f = 0; if (xs2 < vp->v_xs) { xs2 = vp->v_xs; c2 = &mchar_blank; if (ol) { int i = xs2 - vp->v_xoff - 1; if (i >= 0 && i < l->l_width) { copy_mline2mchar(&cc, ol, i); c2 = &cc; } } else f = 1; } if (xe2 > vp->v_xe) xe2 = vp->v_xe; if (xs2 > xe2) continue; display = cv->c_display; if (D_blocked) continue; rol = RECODE_MLINE(ol); InsChar(RECODE_MCHAR(c2), xs2, xe2, y2, mloff(rol, -vp->v_xoff)); if (f) RefreshArea(xs2, y2, xs2, y2, 1); } ); } void LPutChar(struct layer *l, struct mchar *c, int x, int y) { struct canvas *cv; struct viewport *vp; int x2, y2; #ifdef HAVE_BRAILLE if (bd.bd_refreshing) { BPutChar(l, c, x, y); return; } #endif if (l->l_pause.d) LayPauseUpdateRegion(l, x, #ifdef DW_CHARS x + (c->mbcs ? 1 : 0) #else x #endif , y, y); FOR_EACH_UNPAUSED_CANVAS(l, { display = cv->c_display; if (D_blocked) continue; for (vp = cv->c_vplist; vp; vp = vp->v_next) { y2 = y + vp->v_yoff; if (y2 < vp->v_ys || y2 > vp->v_ye) continue; x2 = x + vp->v_xoff; if (x2 < vp->v_xs || x2 > vp->v_xe) continue; PutChar(RECODE_MCHAR(c), x2, y2); break; } } ); } void LPutStr(struct layer *l, char *s, int n, struct mchar *r, int x, int y) { struct canvas *cv; struct viewport *vp; char *s2; int xs2, xe2, y2; if (x + n > l->l_width) n = l->l_width - x; #ifdef HAVE_BRAILLE if (bd.bd_refreshing) { BPutStr(l, s, n, r, x, y); return; } #endif if (l->l_pause.d) LayPauseUpdateRegion(l, x, x + n - 1, y, y); FOR_EACH_UNPAUSED_CANVAS(l, for (vp = cv->c_vplist; vp; vp = vp->v_next) { y2 = y + vp->v_yoff; if (y2 < vp->v_ys || y2 > vp->v_ye) continue; xs2 = x + vp->v_xoff; xe2 = xs2 + n - 1; if (xs2 < vp->v_xs) xs2 = vp->v_xs; if (xe2 > vp->v_xe) xe2 = vp->v_xe; if (xs2 > xe2) continue; display = cv->c_display; if (D_blocked) continue; GotoPos(xs2, y2); SetRendition(r); s2 = s + xs2 - x - vp->v_xoff; #ifdef UTF8 if (D_encoding == UTF8 && l->l_encoding != UTF8 && (r->font || r->fontx || l->l_encoding)) { struct mchar mc; mc = *r; while (xs2 <= xe2) { mc.image = *s2++; PutChar(RECODE_MCHAR(&mc), xs2++, y2); } continue; } #endif while (xs2++ <= xe2) PUTCHARLP(*s2++); } ); } void LPutWinMsg(struct layer *l, char *s, int n, struct mchar *r, int x, int y) { struct canvas *cv; struct viewport *vp; int xs2, xe2, y2, len, len2; struct mchar or; if (x + n > l->l_width) n = l->l_width - x; #ifdef HAVE_BRAILLE if (bd.bd_refreshing) { BPutStr(l, s, n, r, x, y); return; } #endif if (l->l_pause.d) LayPauseUpdateRegion(l, x, x + n - 1, y, y); len = strlen(s); if (len > n) len = n; FOR_EACH_UNPAUSED_CANVAS(l, for (vp = cv->c_vplist; vp; vp = vp->v_next) { y2 = y + vp->v_yoff; if (y2 < vp->v_ys || y2 > vp->v_ye) continue; xs2 = x + vp->v_xoff; xe2 = xs2 + n - 1; if (xs2 < vp->v_xs) xs2 = vp->v_xs; if (xe2 > vp->v_xe) xe2 = vp->v_xe; if (xs2 > xe2) continue; display = cv->c_display; if (D_blocked) continue; GotoPos(xs2, y2); SetRendition(r); len2 = xe2 - (x + vp->v_xoff) + 1; if (len2 > len) len2 = len; PutWinMsg(s, xs2 - x - vp->v_xoff, len2); xs2 = x + vp->v_xoff + len2; if (xs2 < vp->v_xs) xs2 = vp->v_xs; or = D_rend; GotoPos(xs2, y2); SetRendition(&or); while (xs2++ <= xe2) PUTCHARLP(' '); } ); } void LClearLine(struct layer *l, int y, int xs, int xe, int bce, struct mline *ol) { struct canvas *cv; struct viewport *vp; int y2, xs2, xe2; /* check for magic margin condition */ if (xs >= l->l_width) xs = l->l_width - 1; if (xe >= l->l_width) xe = l->l_width - 1; if (l->l_pause.d) LayPauseUpdateRegion(l, xs, xe, y, y); FOR_EACH_UNPAUSED_CANVAS(l, for (vp = cv->c_vplist; vp; vp = vp->v_next) { xs2 = xs + vp->v_xoff; xe2 = xe + vp->v_xoff; y2 = y + vp->v_yoff; if (y2 < vp->v_ys || y2 > vp->v_ye) continue; if (xs2 < vp->v_xs) xs2 = vp->v_xs; if (xe2 > vp->v_xe) xe2 = vp->v_xe; if (xs2 > xe2) continue; display = cv->c_display; if (D_blocked) continue; ClearLine(ol ? mloff(RECODE_MLINE(ol), -vp->v_xoff) : (struct mline *)0, y2, xs2, xe2, bce); } ); } void LClearArea(struct layer *l, int xs, int ys, int xe, int ye, int bce, int uself) { struct canvas *cv; struct viewport *vp; int xs2, ys2, xe2, ye2; #ifdef HAVE_BRAILLE if (bd.bd_refreshing) return; #endif /* Check for zero-height window */ if (ys < 0 || ye < ys) return; /* check for magic margin condition */ if (xs >= l->l_width) xs = l->l_width - 1; if (xe >= l->l_width) xe = l->l_width - 1; if (l->l_pause.d) LayPauseUpdateRegion(l, xs, xe, ys, ye); FOR_EACH_UNPAUSED_CANVAS(l, { display = cv->c_display; if (D_blocked) continue; for (vp = cv->c_vplist; vp; vp = vp->v_next) { xs2 = xs + vp->v_xoff; xe2 = xe + vp->v_xoff; ys2 = ys + vp->v_yoff; ye2 = ye + vp->v_yoff; if (xs2 < vp->v_xs) xs2 = vp->v_xs; if (xe2 > vp->v_xe) xe2 = vp->v_xe; if (xs2 > vp->v_xe) ys2++; if (xe2 < vp->v_xs) ye2--; if (ys2 < vp->v_ys) ys2 = vp->v_ys; if (ye2 > vp->v_ye) ye2 = vp->v_ye; if (ys2 > ye2) continue; #if 0 xcs = vp->v_xoff; xce = l->l_width - 1 + vp->v_xoff; if (xcs < vp->v_xs) xcs = vp->v_xs; if (xce > vp->v_xe) xce = vp->v_xe; if (xcs > xce) continue; if (ys2 != ys + vp->v_yoff) xs2 = xcs; if (ye2 != ye + vp->v_yoff) xe2 = xce; display = cv->c_display; ClearArea(xs2, ys2, xcs, xce, xe2, ye2, bce, uself); #else if (xs == 0 || ys2 != ys + vp->v_yoff) xs2 = vp->v_xs; if (xe == l->l_width - 1 || ye2 != ye + vp->v_yoff) xe2 = vp->v_xe; display = cv->c_display; ClearArea(xs2, ys2, vp->v_xs, vp->v_xe, xe2, ye2, bce, uself); if (xe == l->l_width - 1 && xe2 > vp->v_xoff + xe) { int y; SetRendition(&mchar_blank); for (y = ys2; y <= ye2; y++) { GotoPos(xe + vp->v_xoff + 1, y); PUTCHARLP('|'); } } #endif } } ); } void LCDisplayLine(struct layer *l, struct mline *ml, int y, int xs, int xe, int isblank) { struct canvas *cv; struct viewport *vp; int xs2, xe2, y2; #ifdef HAVE_BRAILLE if (bd.bd_refreshing) { BCDisplayLine(l, ml, y, xs, xe, isblank); return; } #endif if (l->l_pause.d) LayPauseUpdateRegion(l, xs, xe, y, y); FOR_EACH_UNPAUSED_CANVAS(l, { display = cv->c_display; if (D_blocked) continue; for (vp = cv->c_vplist; vp; vp = vp->v_next) { xs2 = xs + vp->v_xoff; xe2 = xe + vp->v_xoff; y2 = y + vp->v_yoff; if (y2 < vp->v_ys || y2 > vp->v_ye) continue; if (xs2 < vp->v_xs) xs2 = vp->v_xs; if (xe2 > vp->v_xe) xe2 = vp->v_xe; if (xs2 > xe2) continue; display = cv->c_display; debug3("LCDisplayLine: DisplayLine %d, %d-%d", y2, xs2, xe2); debug1(" mloff = %d\n", -vp->v_xoff); DisplayLine(isblank ? &mline_blank : &mline_null, mloff(RECODE_MLINE(ml), -vp->v_xoff), y2, xs2, xe2); } } ); } void LCDisplayLineWrap(struct layer *l, struct mline *ml, int y, int from, int to, int isblank) { struct mchar nc; copy_mline2mchar(&nc, ml, 0); #ifdef DW_CHARS if (dw_left(ml, 0, l->l_encoding)) { nc.mbcs = ml->image[1]; from++; } #endif LWrapChar(l, &nc, y - 1, -1, -1, 0); from++; if (from <= to) LCDisplayLine(l, ml, y, from, to, isblank); } void LSetRendition(struct layer *l, struct mchar *r) { struct canvas *cv; for (cv = l->l_cvlist; cv; cv = cv->c_lnext) { display = cv->c_display; if (D_blocked) continue; SetRendition(r); } } void LWrapChar(struct layer *l, struct mchar *c, int y, int top, int bot, int ins) { struct canvas *cv, *cvlist, *cvlnext; struct viewport *vp, *evp, **vpp; int yy, y2, yy2, top2, bot2; int bce; if (l->l_pause.d) /* XXX: 'y'? */ LayPauseUpdateRegion(l, 0, l->l_width - 1, top, bot); #ifdef COLOR bce = rend_getbg(c); #else bce = 0; #endif if (y != bot) { /* simple case: no scrolling */ /* cursor after wrapping */ yy = y == l->l_height - 1 ? y : y + 1; FOR_EACH_UNPAUSED_CANVAS(l, { y2 = 0; /* gcc -Wall */ display = cv->c_display; if (D_blocked) continue; /* find the viewport of the wrapped character */ for (vp = cv->c_vplist; vp; vp = vp->v_next) { y2 = y + vp->v_yoff; yy2 = yy + vp->v_yoff; if (yy2 >= vp->v_ys && yy2 <= vp->v_ye && vp->v_xoff >= vp->v_xs && vp->v_xoff <= vp->v_xe) break; } if (vp == 0) continue; /* nothing to do, character not visible */ /* find the viewport of the character at the end of the line*/ for (evp = cv->c_vplist; evp; evp = evp->v_next) 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) break; /* gotcha! */ if (evp == 0 || (ins && vp->v_xoff + l->l_width - 1 > vp->v_ye)) { /* no wrapping possible */ debug("LWrap: can't wrap!\n"); cvlist = l->l_cvlist; cvlnext = cv->c_lnext; l->l_cvlist = cv; cv->c_lnext = 0; if (ins) LInsChar(l, c, 0, yy, 0); else LPutChar(l, c, 0, yy); l->l_cvlist = cvlist; cv->c_lnext = cvlnext; } else WrapChar(RECODE_MCHAR(c), vp->v_xoff + l->l_width, y2, vp->v_xoff, -1, vp->v_xoff + l->l_width - 1, -1, ins); }); } else { /* hard case: scroll up*/ FOR_EACH_UNPAUSED_CANVAS(l, { display = cv->c_display; if (D_blocked) continue; /* search for wrap viewport */ for (vpp = &cv->c_vplist; (vp = *vpp); vpp = &vp->v_next) { yy2 = bot + vp->v_yoff; 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) break; } if (vp) { /* great, can use Wrap on the vp */ /* temporarily remove vp from cvlist */ *vpp = vp->v_next; } if (cv->c_vplist) { /* scroll all viewports != vp */ cvlist = l->l_cvlist; cvlnext = cv->c_lnext; l->l_cvlist = cv; cv->c_lnext = 0; LScrollV(l, 1, top, bot, bce); if (!vp) { if (ins) LInsChar(l, c, 0, bot, 0); else LPutChar(l, c, 0, bot); } l->l_cvlist = cvlist; cv->c_lnext = cvlnext; } if (vp) { /* add vp back to cvlist */ *vpp = vp; top2 = top + vp->v_yoff; bot2 = bot + vp->v_yoff; if (top2 < vp->v_ys) top2 = vp->v_ys; WrapChar(RECODE_MCHAR(c), vp->v_xoff + l->l_width, bot2, vp->v_xoff, top2, vp->v_xoff + l->l_width - 1, bot2, ins); } }); } } void LCursorVisibility(struct layer *l, int vis) { struct canvas *cv; for (cv = l->l_cvlist; cv; cv = cv->c_lnext) { display = cv->c_display; if (D_blocked) continue; if (cv != D_forecv) continue; CursorVisibility(vis); } } void LSetFlow(struct layer *l, int flow) { struct canvas *cv; for (cv = l->l_cvlist; cv; cv = cv->c_lnext) { display = cv->c_display; if (cv != D_forecv) continue; SetFlow(flow); } } void LKeypadMode(struct layer *l, int on) { struct canvas *cv; for (cv = l->l_cvlist; cv; cv = cv->c_lnext) { display = cv->c_display; if (D_blocked) continue; if (cv != D_forecv) continue; KeypadMode(on); } } void LCursorkeysMode(struct layer *l, int on) { struct canvas *cv; for (cv = l->l_cvlist; cv; cv = cv->c_lnext) { display = cv->c_display; if (D_blocked) continue; if (cv != D_forecv) continue; CursorkeysMode(on); } } void LMouseMode(struct layer *l, int on) { struct canvas *cv; for (cv = l->l_cvlist; cv; cv = cv->c_lnext) { display = cv->c_display; if (D_blocked) continue; if (cv != D_forecv) continue; MouseMode(on); } } void LClearAll(struct layer *l, int uself) { LClearArea(l, 0, 0, l->l_width - 1, l->l_height - 1, 0, uself); } void LRefreshAll(struct layer *l, int isblank) { struct layer *oldflayer; int y; debug1("LRefreshAll isblank=%d\n", isblank); oldflayer = flayer; flayer = l; if (!isblank) LClearArea(l, 0, 0, l->l_width - 1, l->l_height - 1, 0, 0); /* signal full refresh */ LayRedisplayLine(-1, -1, -1, 1); for (y = 0; y < l->l_height; y++) LayRedisplayLine(y, 0, l->l_width - 1, 1); flayer = oldflayer; } void /*VARARGS2*/ #if defined(USEVARARGS) && defined(__STDC__) LMsg(int err, const char *fmt, VA_DOTS) #else LMsg(err, fmt, VA_DOTS) int err; const char *fmt; VA_DECL #endif { VA_LIST(ap) char buf[MAXPATHLEN*2]; char *p = buf; struct canvas *cv; VA_START(ap, fmt); fmt = DoNLS(fmt); (void)vsnprintf(p, sizeof(buf) - 100, fmt, VA_ARGS(ap)); VA_END(ap); if (err) { p += strlen(p); *p++ = ':'; *p++ = ' '; strncpy(p, strerror(err), buf + sizeof(buf) - p - 1); buf[sizeof(buf) - 1] = 0; } debug2("LMsg('%s') (%#x);\n", buf, (unsigned int)flayer); for (display = displays; display; display = display->d_next) { for (cv = D_cvlist; cv; cv = cv->c_next) if (cv->c_layer == flayer) break; if (cv == 0) continue; MakeStatus(buf); } } void LExtMouseMode(l, on) struct layer *l; int on; { struct canvas *cv; for (cv = l->l_cvlist; cv; cv = cv->c_lnext) { display = cv->c_display; if (D_blocked) continue; if (cv != D_forecv) continue; ExtMouseMode(on); } } /*******************************************************************/ /*******************************************************************/ /* * Layer creation / removal */ void KillLayerChain(struct layer *lay) { struct canvas *cv, *ncv; struct layer *l, *oldflayer; oldflayer = flayer; debug1("KillLayerChain %#x\n", lay); for (l = lay; l; l = l->l_next) { if (l->l_layfn == &WinLf || l->l_layfn == &BlankLf) break; debug1("- killing %#x\n", l); if (oldflayer == l) oldflayer = 0; for (cv = l->l_cvlist; cv; cv = ncv) { ncv = cv->c_lnext; cv->c_layer = 0; cv->c_lnext = 0; } } flayer = lay; while (flayer != l) ExitOverlayPage(); flayer = oldflayer; } int InitOverlayPage(int datasize, struct LayFuncs *lf, int block) { char *data; struct layer *newlay; struct canvas *cv, *cvp, **cvpp; struct win *p; ASSERT(flayer); cv = 0; if (display && D_forecv->c_layer == flayer) cv = D_forecv; /* work only on this cv! */ if ((newlay = (struct layer *)calloc(1, sizeof(struct layer))) == 0) { Msg(0, "No memory for layer struct"); return -1; } debug2("Entering new layer on top of %#x: %#x\n", (unsigned int)flayer, newlay); data = 0; if (datasize) { if ((data = calloc(1, datasize)) == 0) { free((char *)newlay); Msg(0, "No memory for layer data"); return -1; } } p = Layer2Window(flayer); if (p && (p->w_savelayer == flayer || (block && flayer->l_next == 0))) { if (p->w_savelayer && p->w_savelayer != flayer && p->w_savelayer->l_cvlist == 0) KillLayerChain(p->w_savelayer); p->w_savelayer = newlay; } if (cv && flayer->l_next == 0 && !block) { struct display *olddisplay = display; display = cv->c_display; RemoveStatus(); display = olddisplay; /* new branch -> just get canvas vps */ for (cvpp = &flayer->l_cvlist; (cvp = *cvpp); cvpp = &cvp->c_lnext) if (cvp == cv) break; ASSERT(cvp); *cvpp = cv->c_lnext; newlay->l_cvlist = cv; cv->c_lnext = 0; cv->c_layer = newlay; } else { LAY_DISPLAYS(flayer, RemoveStatus()); if (block) debug("layer is blocking\n"); if (block && flayer->l_layfn == &WinLf) { debug("...and is first, so window gets blocked\n"); ASSERT(p->w_blocked == 0); p->w_blocked++; newlay->l_blocking = 1; } /* change all canvases */ newlay->l_cvlist = flayer->l_cvlist; for (cvp = newlay->l_cvlist; cvp; cvp = cvp->c_lnext) cvp->c_layer = newlay; flayer->l_cvlist = 0; } newlay->l_width = flayer->l_width; newlay->l_height = flayer->l_height; newlay->l_encoding = 0; newlay->l_layfn = lf; newlay->l_data = data; newlay->l_next = flayer; newlay->l_bottom = flayer->l_bottom; flayer = newlay; LayRestore(); return 0; } extern struct layout *layouts; void ExitOverlayPage() { struct layer *oldlay; struct win *p; int doredisplay = 0; struct canvas *cv, *ocv; struct layout *lay; ASSERT(flayer); debug1("Exiting layer %#x\n", (unsigned int)flayer); oldlay = flayer; if (oldlay->l_data) { if (oldlay->l_layfn->lf_LayFree) LayFree(oldlay->l_data); free(oldlay->l_data); } p = Layer2Window(flayer); flayer = oldlay->l_next; if (flayer->l_layfn == &WinLf) { if (oldlay->l_blocking) { ASSERT(p->w_blocked > 0); p->w_blocked--; debug1("layer was blocking, -> w_blocked now %d\n", p->w_blocked); } /* don't warp dead layers: check cvlist */ if (p->w_blocked && p->w_savelayer && p->w_savelayer != flayer && oldlay->l_cvlist) { debug("warping to top of blocking chain!\n"); /* warp ourself into savelayer */ flayer = p->w_savelayer; doredisplay = 1; } } if (p && p->w_savelayer == oldlay) p->w_savelayer = flayer; #ifdef COPY_PASTE if (p && oldlay == p->w_paster.pa_pastelayer) p->w_paster.pa_pastelayer = 0; #endif for (lay = layouts; lay; lay = lay->lay_next) for (cv = lay->lay_cvlist; cv; cv = cv->c_next) if (cv->c_layer == oldlay) cv->c_layer = flayer; /* add all canvases back into next layer's canvas list */ for (ocv = 0, cv = oldlay->l_cvlist; cv; cv = cv->c_lnext) { cv->c_layer = flayer; ocv = cv; } if (ocv) { cv = flayer->l_cvlist; ocv->c_lnext = 0; flayer->l_cvlist = oldlay->l_cvlist; /* redisplay only the warped cvs */ if (doredisplay) LRefreshAll(flayer, 0); ocv->c_lnext = cv; } oldlay->l_cvlist = 0; LayerCleanupMemory(oldlay); free((char *)oldlay); LayRestore(); LaySetCursor(); } int LayProcessMouse(struct layer *l, unsigned char ch) { /* XXX: Make sure the layer accepts mouse events */ int len; if (l->l_mouseevent.len >= sizeof(l->l_mouseevent.buffer)) return -1; len = l->l_mouseevent.len++; l->l_mouseevent.buffer[len] = (len > 0 ? ch - 33 : ch); return (l->l_mouseevent.len == sizeof(l->l_mouseevent.buffer)); } void LayProcessMouseSwitch(struct layer *l, int s) { if ((l->l_mouseevent.start = s)) l->l_mouseevent.len = 0; } void LayPause(struct layer *layer, int pause) { struct canvas *cv; int line; struct win *win; pause = !!pause; if (layer->l_pause.d == pause) return; if ((layer->l_pause.d = pause)) { /* Start pausing */ layer->l_pause.top = layer->l_pause.bottom = -1; return; } /* Unpause. So refresh the regions in the displays! */ if (layer->l_pause.top == -1 && layer->l_pause.bottom == -1) return; if (layer->l_layfn == &WinLf) /* Currently, this will always be the case! */ win = layer->l_data; else win = NULL; for (cv = layer->l_cvlist; cv; cv = cv->c_lnext) { struct viewport *vp; if (!cv->c_slorient) continue; /* Wasn't split, so already updated. */ display = cv->c_display; for (vp = cv->c_vplist; vp; vp = vp->v_next) { for (line = layer->l_pause.top; line <= layer->l_pause.bottom; line++) { int xs, xe; if (line + vp->v_yoff >= vp->v_ys && line + vp->v_yoff <= vp->v_ye && ((xs = layer->l_pause.left[line]) >= 0) && ((xe = layer->l_pause.right[line]) >= 0)) { xs += vp->v_xoff; xe += vp->v_xoff; if (xs < vp->v_xs) xs = vp->v_xs; if (xe > vp->v_xe) xe = vp->v_xe; #if defined(DW_CHARS) && defined(UTF8) if (layer->l_encoding == UTF8 && xe < vp->v_xe && win) { struct mline *ml = win->w_mlines + line; if (dw_left(ml, xe, UTF8)) xe++; } #endif if (xs <= xe) RefreshLine(line + vp->v_yoff, xs, xe, 0); } } } if (cv == D_forecv) { int cx = layer->l_x + cv->c_xoff; int cy = layer->l_y + cv->c_yoff; if (cx < cv->c_xs) cx = cv->c_xs; if (cy < cv->c_ys) cy = cv->c_ys; if (cx > cv->c_xe) cx = cv->c_xe; if (cy > cv->c_ye) cy = cv->c_ye; GotoPos(cx, cy); } } for (line = layer->l_pause.top; line <= layer->l_pause.bottom; line++) layer->l_pause.left[line] = layer->l_pause.right[line] = -1; } void LayPauseUpdateRegion(struct layer *layer, int xs, int xe, int ys, int ye) { if (!layer->l_pause.d) return; if (ys < 0) ys = 0; if (ye >= layer->l_height) ye = layer->l_height - 1; if (xe >= layer->l_width) xe = layer->l_width - 1; if (layer->l_pause.top == -1 || layer->l_pause.top > ys) layer->l_pause.top = ys; if (layer->l_pause.bottom < ye) { layer->l_pause.bottom = ye; if (layer->l_pause.lines <= ye) { int o = layer->l_pause.lines; layer->l_pause.lines = ye + 32; layer->l_pause.left = realloc(layer->l_pause.left, sizeof(int) * layer->l_pause.lines); layer->l_pause.right = realloc(layer->l_pause.right, sizeof(int) * layer->l_pause.lines); while (o < layer->l_pause.lines) { layer->l_pause.left[o] = layer->l_pause.right[o] = -1; o++; } } } while (ys <= ye) { if (layer->l_pause.left[ys] == -1 || layer->l_pause.left[ys] > xs) layer->l_pause.left[ys] = xs; if (layer->l_pause.right[ys] < xe) layer->l_pause.right[ys] = xe; ys++; } } void LayerCleanupMemory(struct layer *layer) { if (layer->l_pause.left) free(layer->l_pause.left); if (layer->l_pause.right) free(layer->l_pause.right); }