summaryrefslogtreecommitdiff
path: root/libmemlayer
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /libmemlayer
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'libmemlayer')
-rw-r--r--libmemlayer/NOTICE29
-rw-r--r--libmemlayer/draw.c192
-rw-r--r--libmemlayer/lalloc-x11.c185
-rw-r--r--libmemlayer/lalloc.c78
-rw-r--r--libmemlayer/layerop.c111
-rw-r--r--libmemlayer/ldelete.c66
-rw-r--r--libmemlayer/lhide.c67
-rw-r--r--libmemlayer/line.c121
-rw-r--r--libmemlayer/load.c54
-rw-r--r--libmemlayer/lorigin.c106
-rw-r--r--libmemlayer/lreshape.c0
-rw-r--r--libmemlayer/lsetrefresh.c34
-rw-r--r--libmemlayer/ltofront.c80
-rw-r--r--libmemlayer/ltorear.c68
-rw-r--r--libmemlayer/mkfile26
-rw-r--r--libmemlayer/mkfile-FreeBSD4
-rw-r--r--libmemlayer/mkfile-Hp4
-rw-r--r--libmemlayer/mkfile-Inferno4
-rw-r--r--libmemlayer/mkfile-Irix4
-rw-r--r--libmemlayer/mkfile-Linux4
-rw-r--r--libmemlayer/mkfile-MacOSX4
-rw-r--r--libmemlayer/mkfile-NetBSD4
-rw-r--r--libmemlayer/mkfile-Nt4
-rw-r--r--libmemlayer/mkfile-Plan94
-rw-r--r--libmemlayer/mkfile-Posix4
-rw-r--r--libmemlayer/mkfile-Solaris4
-rw-r--r--libmemlayer/mkfile-Unixware4
-rw-r--r--libmemlayer/mkfile-os4
-rw-r--r--libmemlayer/unload.c51
29 files changed, 1320 insertions, 0 deletions
diff --git a/libmemlayer/NOTICE b/libmemlayer/NOTICE
new file mode 100644
index 00000000..d2099067
--- /dev/null
+++ b/libmemlayer/NOTICE
@@ -0,0 +1,29 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory. If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below. It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2006 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/libmemlayer/draw.c b/libmemlayer/draw.c
new file mode 100644
index 00000000..94110d6c
--- /dev/null
+++ b/libmemlayer/draw.c
@@ -0,0 +1,192 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+#include "pool.h"
+
+struct Draw
+{
+ Point deltas;
+ Point deltam;
+ Memlayer *dstlayer;
+ Memimage *src;
+ Memimage *mask;
+ int op;
+};
+
+static
+void
+ldrawop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave)
+{
+ struct Draw *d;
+ Point p0, p1;
+ Rectangle oclipr, srcr, r, mr;
+ int ok;
+
+ d = etc;
+ if(insave && d->dstlayer->save==nil)
+ return;
+
+ p0 = addpt(screenr.min, d->deltas);
+ p1 = addpt(screenr.min, d->deltam);
+
+ if(insave){
+ r = rectsubpt(screenr, d->dstlayer->delta);
+ clipr = rectsubpt(clipr, d->dstlayer->delta);
+ }else
+ r = screenr;
+
+ /* now in logical coordinates */
+
+ /* clipr may have narrowed what we should draw on, so clip if necessary */
+ if(!rectinrect(r, clipr)){
+ oclipr = dst->clipr;
+ dst->clipr = clipr;
+ ok = drawclip(dst, &r, d->src, &p0, d->mask, &p1, &srcr, &mr);
+ dst->clipr = oclipr;
+ if(!ok)
+ return;
+ }
+ memdraw(dst, r, d->src, p0, d->mask, p1, d->op);
+}
+
+void
+memdraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op)
+{
+ struct Draw d;
+ Rectangle srcr, tr, mr;
+ Memlayer *dl, *sl;
+
+ if(drawdebug)
+ iprint("memdraw %p %R %p %P %p %P\n", dst, r, src, p0, mask, p1);
+
+ if(mask == nil)
+ mask = memopaque;
+
+ if(mask->layer){
+if(drawdebug) iprint("mask->layer != nil\n");
+ return; /* too hard, at least for now */
+ }
+
+ Top:
+ if(dst->layer==nil && src->layer==nil){
+ memimagedraw(dst, r, src, p0, mask, p1, op);
+ return;
+ }
+
+ if(drawclip(dst, &r, src, &p0, mask, &p1, &srcr, &mr) == 0){
+if(drawdebug) iprint("drawclip dstcr %R srccr %R maskcr %R\n", dst->clipr, src->clipr, mask->clipr);
+ return;
+ }
+
+ /*
+ * Convert to screen coordinates.
+ */
+ dl = dst->layer;
+ if(dl != nil){
+ r.min.x += dl->delta.x;
+ r.min.y += dl->delta.y;
+ r.max.x += dl->delta.x;
+ r.max.y += dl->delta.y;
+ }
+ Clearlayer:
+ if(dl!=nil && dl->clear){
+ if(src == dst){
+ p0.x += dl->delta.x;
+ p0.y += dl->delta.y;
+ src = dl->screen->image;
+ }
+ dst = dl->screen->image;
+ goto Top;
+ }
+
+ sl = src->layer;
+ if(sl != nil){
+ p0.x += sl->delta.x;
+ p0.y += sl->delta.y;
+ srcr.min.x += sl->delta.x;
+ srcr.min.y += sl->delta.y;
+ srcr.max.x += sl->delta.x;
+ srcr.max.y += sl->delta.y;
+ }
+
+ /*
+ * Now everything is in screen coordinates.
+ * mask is an image. dst and src are images or obscured layers.
+ */
+
+ /*
+ * if dst and src are the same layer, just draw in save area and expose.
+ */
+ if(dl!=nil && dst==src){
+ if(dl->save == nil)
+ return; /* refresh function makes this case unworkable */
+ if(rectXrect(r, srcr)){
+ tr = r;
+ if(srcr.min.x < tr.min.x){
+ p1.x += tr.min.x - srcr.min.x;
+ tr.min.x = srcr.min.x;
+ }
+ if(srcr.min.y < tr.min.y){
+ p1.y += tr.min.x - srcr.min.x;
+ tr.min.y = srcr.min.y;
+ }
+ if(srcr.max.x > tr.max.x)
+ tr.max.x = srcr.max.x;
+ if(srcr.max.y > tr.max.y)
+ tr.max.y = srcr.max.y;
+ memlhide(dst, tr);
+ }else{
+ memlhide(dst, r);
+ memlhide(dst, srcr);
+ }
+ memdraw(dl->save, rectsubpt(r, dl->delta), dl->save,
+ subpt(srcr.min, src->layer->delta), mask, p1, op);
+ memlexpose(dst, r);
+ return;
+ }
+
+ if(sl){
+ if(sl->clear){
+ src = sl->screen->image;
+ if(dl != nil){
+ r.min.x -= dl->delta.x;
+ r.min.y -= dl->delta.y;
+ r.max.x -= dl->delta.x;
+ r.max.y -= dl->delta.y;
+ }
+ goto Top;
+ }
+ /* relatively rare case; use save area */
+ if(sl->save == nil)
+ return; /* refresh function makes this case unworkable */
+ memlhide(src, srcr);
+ /* convert back to logical coordinates */
+ p0.x -= sl->delta.x;
+ p0.y -= sl->delta.y;
+ srcr.min.x -= sl->delta.x;
+ srcr.min.y -= sl->delta.y;
+ srcr.max.x -= sl->delta.x;
+ srcr.max.y -= sl->delta.y;
+ src = src->layer->save;
+ }
+
+ /*
+ * src is now an image. dst may be an image or a clear layer
+ */
+ if(dst->layer==nil)
+ goto Top;
+ if(dst->layer->clear)
+ goto Clearlayer;
+
+ /*
+ * dst is an obscured layer
+ */
+ d.deltas = subpt(p0, r.min);
+ d.deltam = subpt(p1, r.min);
+ d.dstlayer = dl;
+ d.src = src;
+ d.mask = mask;
+ d.op = op;
+ _memlayerop(ldrawop, dst, r, r, &d);
+}
diff --git a/libmemlayer/lalloc-x11.c b/libmemlayer/lalloc-x11.c
new file mode 100644
index 00000000..6a361853
--- /dev/null
+++ b/libmemlayer/lalloc-x11.c
@@ -0,0 +1,185 @@
+#include "lib9.h"
+#include "image.h"
+#include "memimage.h"
+#include "memlayer.h"
+
+#include "../memimage/xmem.h"
+
+
+static ulong colorword;
+static Memdata colordata = {
+ nil,
+ &colorword
+};
+
+static Memimage paint =
+{
+ { 0, 0, 1, 1 },
+ { -1000000, -1000000, 10000000, 1000000 },
+ 0,
+ 1,
+ &colordata,
+ 0,
+ 1,
+ 0,
+};
+
+static Memimage *xpaint;
+
+static void
+setcolor(int val, int ldepth)
+{
+ int bpp;
+
+ paint.ldepth = ldepth;
+ bpp = 1<<ldepth;
+ val &= ~(0xFF>>bpp);
+ /* color is now in low part of word; replicate through pixel */
+ for(; bpp<32; bpp<<=1)
+ val |= val<<bpp;
+ colorword = val;
+}
+
+ulong*
+makememones(void)
+{
+ Xmem *xm;
+ extern Memimage screenimage;
+ extern void drawreset();
+
+ if(memones->X)
+ return;
+ drawreset();
+ /* set up screen pixmap */
+ xm = malloc(sizeof(Xmem));
+ if(xm == nil){
+ print("can't alloc for screen pixmap\n");
+ return;
+ }
+ if(screenimage.ldepth == 0)
+ xm->pmid0 = xscreenid;
+ else
+ xm->pmid0 = PMundef;
+ xm->pmid = xscreenid;
+ xm->wordp = &xm->word;
+ screenimage.X = xm;
+ screenimage.data->data = &xm->word;
+
+ memones = allocmemimage(paint.r, paint.ldepth);
+ memones->clipr = paint.clipr;
+ memones->repl = 1;
+ memfillcolor(memones, ~0);
+
+ return screenimage.data->data;
+}
+
+Memimage*
+memlalloc(Memscreen *s, Rectangle screenr, Refreshfn refreshfn, void *refreshptr, int val)
+{
+ Memimage *n;
+ Memlayer *l;
+ Xmem *xm, *sxm;
+
+ n = malloc(sizeof(Memimage));
+ if(n == nil)
+ return nil;
+
+ l = malloc(sizeof(Memlayer));
+ if(l == nil){
+ free(n);
+ return nil;
+ }
+
+ xm = malloc(sizeof(Xmem));
+ if(xm == nil){
+ free(l);
+ free(n);
+ return nil;
+ }
+
+ if(refreshfn) {
+ l->save = nil;
+ }
+ else{
+ l->save = allocmemimage(screenr, s->image->ldepth);
+ if(l->save == nil){
+ free(l);
+ free(n);
+ free(xm);
+ return nil;
+ }
+
+ /* allocmemimage doesn't initialize memory; this paints save area */
+ if(val >= 0)
+ memfillcolor(l->save, val);
+ }
+
+ n->r = screenr;
+ n->clipr = screenr;
+ n->ldepth = s->image->ldepth;
+ n->repl = 0;
+ n->data = s->image->data;
+ n->zero = s->image->zero;
+ n->width = s->image->width;
+ n->layer = l;
+ n->X = xm;
+
+ sxm = s->image->X;
+ xm->pmid0 = sxm->pmid0;
+ xm->pmid = sxm->pmid;
+ xm->flag = 0;
+ xm->wordp = sxm->wordp;
+
+ l->screen = s;
+ l->refreshfn = refreshfn;
+ l->screenr = screenr;
+ l->delta = Pt(0,0);
+
+ /* start with new window behind all existing ones */
+ l->front = s->rearmost;
+ l->rear = nil;
+ if(s->rearmost)
+ s->rearmost->layer->rear = n;
+ s->rearmost = n;
+ if(s->frontmost == nil)
+ s->frontmost = n;
+ l->clear = 0;
+
+ /* don't set it until we're done */
+ l->refreshptr = nil;
+
+ /* now pull new window to front */
+ memltofront(n);
+
+ /* now we're done */
+ l->refreshptr = refreshptr;
+
+ /*
+ * paint with requested color.
+ * previously exposed areas are already right
+ * if this window has backing store, but just painting
+ * the whole thing is simplest.
+ */
+
+ if(val >= 0){
+ setcolor(val, s->image->ldepth);
+ if(xpaint == nil){
+ xpaint = allocmemimage(paint.r, paint.ldepth);
+ if(xpaint == nil) {
+ if(l->save != nil)
+ freememimage(l->save);
+ free(l);
+ free(n);
+ free(xm);
+ return nil;
+ }
+ xpaint->clipr = paint.clipr;
+ xpaint->repl = 1;
+ }
+ ((Xmem*)(xpaint->X))->word = colorword;
+ ((Xmem*)(xpaint->X))->flag |= XXonepixel;
+ memfillcolor(xpaint, val);
+ memdraw(n, n->r, xpaint, n->r.min, memones, n->r.min, S);
+ }
+ return n;
+}
diff --git a/libmemlayer/lalloc.c b/libmemlayer/lalloc.c
new file mode 100644
index 00000000..0dee2a13
--- /dev/null
+++ b/libmemlayer/lalloc.c
@@ -0,0 +1,78 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+Memimage*
+memlalloc(Memscreen *s, Rectangle screenr, Refreshfn refreshfn, void *refreshptr, ulong val)
+{
+ Memlayer *l;
+ Memimage *n;
+ static Memimage *paint;
+
+ if(paint == nil){
+ paint = allocmemimage(Rect(0,0,1,1), RGBA32);
+ if(paint == nil)
+ return nil;
+ paint->flags |= Frepl;
+ paint->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
+ }
+
+ n = allocmemimaged(screenr, s->image->chan, s->image->data);
+ if(n == nil)
+ return nil;
+ l = malloc(sizeof(Memlayer));
+ if(l == nil){
+ free(n);
+ return nil;
+ }
+
+ l->screen = s;
+ if(refreshfn)
+ l->save = nil;
+ else{
+ l->save = allocmemimage(screenr, s->image->chan);
+ if(l->save == nil){
+ free(l);
+ free(n);
+ return nil;
+ }
+ /* allocmemimage doesn't initialize memory; this paints save area */
+ if(val != DNofill)
+ memfillcolor(l->save, val);
+ }
+ l->refreshfn = refreshfn;
+ l->refreshptr = nil; /* don't set it until we're done */
+ l->screenr = screenr;
+ l->delta = Pt(0,0);
+
+ n->data->ref++;
+ n->zero = s->image->zero;
+ n->width = s->image->width;
+ n->layer = l;
+
+ /* start with new window behind all existing ones */
+ l->front = s->rearmost;
+ l->rear = nil;
+ if(s->rearmost)
+ s->rearmost->layer->rear = n;
+ s->rearmost = n;
+ if(s->frontmost == nil)
+ s->frontmost = n;
+ l->clear = 0;
+
+ /* now pull new window to front */
+ _memltofrontfill(n, val != DNofill);
+ l->refreshptr = refreshptr;
+
+ /*
+ * paint with requested color; previously exposed areas are already right
+ * if this window has backing store, but just painting the whole thing is simplest.
+ */
+ if(val != DNofill){
+ memsetchan(paint, n->chan);
+ memfillcolor(paint, val);
+ memdraw(n, n->r, paint, n->r.min, nil, n->r.min, S);
+ }
+ return n;
+}
diff --git a/libmemlayer/layerop.c b/libmemlayer/layerop.c
new file mode 100644
index 00000000..042adce5
--- /dev/null
+++ b/libmemlayer/layerop.c
@@ -0,0 +1,111 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+#define RECUR(a,b,c,d) _layerop(fn, i, Rect(a.x, b.y, c.x, d.y), clipr, etc, front->layer->rear);
+
+static void
+_layerop(
+ void (*fn)(Memimage*, Rectangle, Rectangle, void*, int),
+ Memimage *i,
+ Rectangle r,
+ Rectangle clipr,
+ void *etc,
+ Memimage *front)
+{
+ Rectangle fr;
+
+ Top:
+ if(front == i){
+ /* no one is in front of this part of window; use the screen */
+ fn(i->layer->screen->image, r, clipr, etc, 0);
+ return;
+ }
+ fr = front->layer->screenr;
+ if(rectXrect(r, fr) == 0){
+ /* r doesn't touch this window; continue on next rearmost */
+ /* assert(front && front->layer && front->layer->screen && front->layer->rear); */
+ front = front->layer->rear;
+ goto Top;
+ }
+ if(fr.max.y < r.max.y){
+ RECUR(r.min, fr.max, r.max, r.max);
+ r.max.y = fr.max.y;
+ }
+ if(r.min.y < fr.min.y){
+ RECUR(r.min, r.min, r.max, fr.min);
+ r.min.y = fr.min.y;
+ }
+ if(fr.max.x < r.max.x){
+ RECUR(fr.max, r.min, r.max, r.max);
+ r.max.x = fr.max.x;
+ }
+ if(r.min.x < fr.min.x){
+ RECUR(r.min, r.min, fr.min, r.max);
+ r.min.x = fr.min.x;
+ }
+ /* r is covered by front, so put in save area */
+ (*fn)(i->layer->save, r, clipr, etc, 1);
+}
+
+/*
+ * Assumes incoming rectangle has already been clipped to i's logical r and clipr
+ */
+void
+_memlayerop(
+ void (*fn)(Memimage*, Rectangle, Rectangle, void*, int),
+ Memimage *i,
+ Rectangle screenr, /* clipped to window boundaries */
+ Rectangle clipr, /* clipped also to clipping rectangles of hierarchy */
+ void *etc)
+{
+ Memlayer *l;
+ Rectangle r, scr;
+
+ l = i->layer;
+ if(!rectclip(&screenr, l->screenr))
+ return;
+ if(l->clear){
+ fn(l->screen->image, screenr, clipr, etc, 0);
+ return;
+ }
+ r = screenr;
+ scr = l->screen->image->clipr;
+
+ /*
+ * Do the piece on the screen
+ */
+ if(rectclip(&screenr, scr))
+ _layerop(fn, i, screenr, clipr, etc, l->screen->frontmost);
+ if(rectinrect(r, scr))
+ return;
+
+ /*
+ * Do the piece off the screen
+ */
+ if(!rectXrect(r, scr)){
+ /* completely offscreen; easy */
+ fn(l->save, r, clipr, etc, 1);
+ return;
+ }
+ if(r.min.y < scr.min.y){
+ /* above screen */
+ fn(l->save, Rect(r.min.x, r.min.y, r.max.x, scr.min.y), clipr, etc, 1);
+ r.min.y = scr.min.y;
+ }
+ if(r.max.y > scr.max.y){
+ /* below screen */
+ fn(l->save, Rect(r.min.x, scr.max.y, r.max.x, r.max.y), clipr, etc, 1);
+ r.max.y = scr.max.y;
+ }
+ if(r.min.x < scr.min.x){
+ /* left of screen */
+ fn(l->save, Rect(r.min.x, r.min.y, scr.min.x, r.max.y), clipr, etc, 1);
+ r.min.x = scr.min.x;
+ }
+ if(r.max.x > scr.max.x){
+ /* right of screen */
+ fn(l->save, Rect(scr.max.x, r.min.y, r.max.x, r.max.y), clipr, etc, 1);
+ }
+}
diff --git a/libmemlayer/ldelete.c b/libmemlayer/ldelete.c
new file mode 100644
index 00000000..fdf4fb65
--- /dev/null
+++ b/libmemlayer/ldelete.c
@@ -0,0 +1,66 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+void
+memldelete(Memimage *i)
+{
+ Memscreen *s;
+ Memlayer *l;
+
+ l = i->layer;
+ /* free backing store and disconnect refresh, to make pushback fast */
+ freememimage(l->save);
+ l->save = nil;
+ l->refreshptr = nil;
+ memltorear(i);
+
+ /* window is now the rearmost; clean up screen structures and deallocate */
+ s = i->layer->screen;
+ if(s->fill){
+ i->clipr = i->r;
+ memdraw(i, i->r, s->fill, i->r.min, nil, i->r.min, S);
+ }
+ if(l->front){
+ l->front->layer->rear = nil;
+ s->rearmost = l->front;
+ }else{
+ s->frontmost = nil;
+ s->rearmost = nil;
+ }
+ free(l);
+ freememimage(i);
+}
+
+/*
+ * Just free the data structures, don't do graphics
+ */
+void
+memlfree(Memimage *i)
+{
+ Memlayer *l;
+
+ l = i->layer;
+ freememimage(l->save);
+ free(l);
+ freememimage(i);
+}
+
+void
+_memlsetclear(Memscreen *s)
+{
+ Memimage *i, *j;
+ Memlayer *l;
+
+ for(i=s->rearmost; i; i=i->layer->front){
+ l = i->layer;
+ l->clear = rectinrect(l->screenr, l->screen->image->clipr);
+ if(l->clear)
+ for(j=l->front; j; j=j->layer->front)
+ if(rectXrect(l->screenr, j->layer->screenr)){
+ l->clear = 0;
+ break;
+ }
+ }
+}
diff --git a/libmemlayer/lhide.c b/libmemlayer/lhide.c
new file mode 100644
index 00000000..30fd8a1c
--- /dev/null
+++ b/libmemlayer/lhide.c
@@ -0,0 +1,67 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+#include "pool.h"
+
+/*
+ * Hide puts that portion of screenr now on the screen into the window's save area.
+ * Expose puts that portion of screenr now in the save area onto the screen.
+ *
+ * Hide and Expose both require that the layer structures in the screen
+ * match the geometry they are being asked to update, that is, they update the
+ * save area (hide) or screen (expose) based on what those structures tell them.
+ * This means they must be called at the correct time during window shuffles.
+ */
+
+static
+void
+lhideop(Memimage *src, Rectangle screenr, Rectangle clipr, void *etc, int insave)
+{
+ Rectangle r;
+ Memlayer *l;
+
+ USED(clipr.min.x);
+ USED(insave);
+ l = etc;
+ if(src != l->save){ /* do nothing if src is already in save area */
+ r = rectsubpt(screenr, l->delta);
+ memdraw(l->save, r, src, screenr.min, nil, screenr.min, S);
+ }
+}
+
+void
+memlhide(Memimage *i, Rectangle screenr)
+{
+ if(i->layer->save == nil)
+ return;
+ if(rectclip(&screenr, i->layer->screen->image->r) == 0)
+ return;
+ _memlayerop(lhideop, i, screenr, screenr, i->layer);
+}
+
+static
+void
+lexposeop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave)
+{
+ Memlayer *l;
+ Rectangle r;
+
+ USED(clipr.min.x);
+ if(insave) /* if dst is save area, don't bother */
+ return;
+ l = etc;
+ r = rectsubpt(screenr, l->delta);
+ if(l->save)
+ memdraw(dst, screenr, l->save, r.min, nil, r.min, S);
+ else
+ l->refreshfn(dst, r, l->refreshptr);
+}
+
+void
+memlexpose(Memimage *i, Rectangle screenr)
+{
+ if(rectclip(&screenr, i->layer->screen->image->r) == 0)
+ return;
+ _memlayerop(lexposeop, i, screenr, screenr, i->layer);
+}
diff --git a/libmemlayer/line.c b/libmemlayer/line.c
new file mode 100644
index 00000000..06e8a41a
--- /dev/null
+++ b/libmemlayer/line.c
@@ -0,0 +1,121 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+struct Lline
+{
+ Point p0;
+ Point p1;
+ Point delta;
+ int end0;
+ int end1;
+ int radius;
+ Point sp;
+ Memlayer *dstlayer;
+ Memimage *src;
+ int op;
+};
+
+static void llineop(Memimage*, Rectangle, Rectangle, void*, int);
+
+static
+void
+_memline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, Rectangle clipr, int op)
+{
+ Rectangle r;
+ struct Lline ll;
+ Point d;
+ int srcclipped;
+ Memlayer *dl;
+
+ if(radius < 0)
+ return;
+ if(src->layer) /* can't draw line with layered source */
+ return;
+ srcclipped = 0;
+
+ Top:
+ dl = dst->layer;
+ if(dl == nil){
+ _memimageline(dst, p0, p1, end0, end1, radius, src, sp, clipr, op);
+ return;
+ }
+ if(!srcclipped){
+ d = subpt(sp, p0);
+ if(rectclip(&clipr, rectsubpt(src->clipr, d)) == 0)
+ return;
+ if((src->flags&Frepl)==0 && rectclip(&clipr, rectsubpt(src->r, d))==0)
+ return;
+ srcclipped = 1;
+ }
+
+ /* dst is known to be a layer */
+ p0.x += dl->delta.x;
+ p0.y += dl->delta.y;
+ p1.x += dl->delta.x;
+ p1.y += dl->delta.y;
+ clipr.min.x += dl->delta.x;
+ clipr.min.y += dl->delta.y;
+ clipr.max.x += dl->delta.x;
+ clipr.max.y += dl->delta.y;
+ if(dl->clear){
+ dst = dst->layer->screen->image;
+ goto Top;
+ }
+
+ /* XXX */
+ /* this is not the correct set of tests */
+// if(log2[dst->depth] != log2[src->depth] || log2[dst->depth]!=3)
+// return;
+
+ /* can't use sutherland-cohen clipping because lines are wide */
+ r = memlinebbox(p0, p1, end0, end1, radius);
+ /*
+ * r is now a bounding box for the line;
+ * use it as a clipping rectangle for subdivision
+ */
+ if(rectclip(&r, clipr) == 0)
+ return;
+ ll.p0 = p0;
+ ll.p1 = p1;
+ ll.end0 = end0;
+ ll.end1 = end1;
+ ll.sp = sp;
+ ll.dstlayer = dst->layer;
+ ll.src = src;
+ ll.radius = radius;
+ ll.delta = dl->delta;
+ ll.op = op;
+ _memlayerop(llineop, dst, r, r, &ll);
+}
+
+static
+void
+llineop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave)
+{
+ struct Lline *ll;
+ Point p0, p1;
+
+ USED(screenr.min.x);
+ ll = etc;
+ if(insave && ll->dstlayer->save==nil)
+ return;
+ if(!rectclip(&clipr, screenr))
+ return;
+ if(insave){
+ p0 = subpt(ll->p0, ll->delta);
+ p1 = subpt(ll->p1, ll->delta);
+ clipr = rectsubpt(clipr, ll->delta);
+ }else{
+ p0 = ll->p0;
+ p1 = ll->p1;
+ }
+ _memline(dst, p0, p1, ll->end0, ll->end1, ll->radius, ll->src, ll->sp, clipr, ll->op);
+}
+
+void
+memline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, int op)
+{
+ _memline(dst, p0, p1, end0, end1, radius, src, sp, dst->clipr, op);
+}
diff --git a/libmemlayer/load.c b/libmemlayer/load.c
new file mode 100644
index 00000000..882dae60
--- /dev/null
+++ b/libmemlayer/load.c
@@ -0,0 +1,54 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+int
+memload(Memimage *dst, Rectangle r, uchar *data, int n, int iscompressed)
+{
+ int (*loadfn)(Memimage*, Rectangle, uchar*, int);
+ Memimage *tmp;
+ Memlayer *dl;
+ Rectangle lr;
+ int dx;
+
+ loadfn = loadmemimage;
+ if(iscompressed)
+ loadfn = cloadmemimage;
+
+ Top:
+ dl = dst->layer;
+ if(dl == nil)
+ return loadfn(dst, r, data, n);
+
+ /*
+ * Convert to screen coordinates.
+ */
+ lr = r;
+ r.min.x += dl->delta.x;
+ r.min.y += dl->delta.y;
+ r.max.x += dl->delta.x;
+ r.max.y += dl->delta.y;
+ dx = dl->delta.x&(7/dst->depth);
+ if(dl->clear && dx==0){
+ dst = dl->screen->image;
+ goto Top;
+ }
+
+ /*
+ * dst is an obscured layer or data is unaligned
+ */
+ if(dl->save && dx==0){
+ n = loadfn(dl->save, lr, data, n);
+ if(n > 0)
+ memlexpose(dst, r);
+ return n;
+ }
+ tmp = allocmemimage(lr, dst->chan);
+ if(tmp == nil)
+ return -1;
+ n = loadfn(tmp, lr, data, n);
+ memdraw(dst, lr, tmp, lr.min, nil, lr.min, S);
+ freememimage(tmp);
+ return n;
+}
diff --git a/libmemlayer/lorigin.c b/libmemlayer/lorigin.c
new file mode 100644
index 00000000..ba37f65c
--- /dev/null
+++ b/libmemlayer/lorigin.c
@@ -0,0 +1,106 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+/*
+ * Place i so i->r.min = log, i->layer->screenr.min == scr.
+*/
+int
+memlorigin(Memimage *i, Point log, Point scr)
+{
+ Memlayer *l;
+ Memscreen *s;
+ Memimage *t, *shad, *nsave;
+ Rectangle x, newr, oldr;
+ Point delta;
+ int overlap, eqlog, eqscr, wasclear;
+
+ l = i->layer;
+ s = l->screen;
+ oldr = l->screenr;
+ newr = Rect(scr.x, scr.y, scr.x+Dx(oldr), scr.y+Dy(oldr));
+ eqscr = eqpt(scr, oldr.min);
+ eqlog = eqpt(log, i->r.min);
+ if(eqscr && eqlog)
+ return 0;
+ nsave = nil;
+ if(eqlog==0 && l->save!=nil){
+ nsave = allocmemimage(Rect(log.x, log.y, log.x+Dx(oldr), log.y+Dy(oldr)), i->chan);
+ if(nsave == nil)
+ return -1;
+ }
+
+ /*
+ * Bring it to front and move logical coordinate system.
+ */
+ memltofront(i);
+ wasclear = l->clear;
+ if(nsave){
+ if(!wasclear)
+ memimagedraw(nsave, nsave->r, l->save, l->save->r.min, nil, Pt(0,0), S);
+ freememimage(l->save);
+ l->save = nsave;
+ }
+ delta = subpt(log, i->r.min);
+ i->r = rectaddpt(i->r, delta);
+ i->clipr = rectaddpt(i->clipr, delta);
+ l->delta = subpt(l->screenr.min, i->r.min);
+ if(eqscr)
+ return 0;
+
+ /*
+ * To clean up old position, make a shadow window there, don't paint it,
+ * push it behind this one, and (later) delete it. Because the refresh function
+ * for this fake window is a no-op, this will cause no graphics action except
+ * to restore the background and expose the windows previously hidden.
+ */
+ shad = memlalloc(s, oldr, memlnorefresh, nil, DNofill);
+ if(shad == nil)
+ return -1;
+ s->frontmost = i;
+ if(s->rearmost == i)
+ s->rearmost = shad;
+ else
+ l->rear->layer->front = shad;
+ shad->layer->front = i;
+ shad->layer->rear = l->rear;
+ l->rear = shad;
+ l->front = nil;
+ shad->layer->clear = 0;
+
+ /*
+ * Shadow is now holding down the fort at the old position.
+ * Move the window and hide things obscured by new position.
+ */
+ for(t=l->rear->layer->rear; t!=nil; t=t->layer->rear){
+ x = newr;
+ overlap = rectclip(&x, t->layer->screenr);
+ if(overlap){
+ memlhide(t, x);
+ t->layer->clear = 0;
+ }
+ }
+ l->screenr = newr;
+ l->delta = subpt(scr, i->r.min);
+ l->clear = rectinrect(newr, l->screen->image->clipr);
+
+ /*
+ * Everything's covered. Copy to new position and delete shadow window.
+ */
+ if(wasclear)
+ memdraw(s->image, newr, s->image, oldr.min, nil, Pt(0,0), S);
+ else
+ memlexpose(i, newr);
+ memldelete(shad);
+
+ return 1;
+}
+
+void
+memlnorefresh(Memimage *l, Rectangle r, void *v)
+{
+ USED(l);
+ USED(r.min.x);
+ USED(v);
+}
diff --git a/libmemlayer/lreshape.c b/libmemlayer/lreshape.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/libmemlayer/lreshape.c
diff --git a/libmemlayer/lsetrefresh.c b/libmemlayer/lsetrefresh.c
new file mode 100644
index 00000000..fbd7b9c5
--- /dev/null
+++ b/libmemlayer/lsetrefresh.c
@@ -0,0 +1,34 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+int
+memlsetrefresh(Memimage *i, Refreshfn fn, void *ptr)
+{
+ Memlayer *l;
+
+ l = i->layer;
+ if(l->refreshfn!=nil && fn!=nil){ /* just change functions */
+ l->refreshfn = fn;
+ l->refreshptr = ptr;
+ return 1;
+ }
+
+ if(l->refreshfn == nil){ /* is using backup image; just free it */
+ freememimage(l->save);
+ l->save = nil;
+ l->refreshfn = fn;
+ l->refreshptr = ptr;
+ return 1;
+ }
+
+ l->save = allocmemimage(i->r, i->chan);
+ if(l->save == nil)
+ return 0;
+ /* easiest way is just to update the entire save area */
+ l->refreshfn(i, i->r, l->refreshptr);
+ l->refreshfn = nil;
+ l->refreshptr = nil;
+ return 1;
+}
diff --git a/libmemlayer/ltofront.c b/libmemlayer/ltofront.c
new file mode 100644
index 00000000..04066ca1
--- /dev/null
+++ b/libmemlayer/ltofront.c
@@ -0,0 +1,80 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+#include "pool.h"
+
+/*
+ * Pull i towards top of screen, just behind front
+*/
+static
+void
+_memltofront(Memimage *i, Memimage *front, int fill)
+{
+ Memlayer *l;
+ Memscreen *s;
+ Memimage *f, *ff, *rr;
+ Rectangle x;
+ int overlap;
+
+ l = i->layer;
+ s = l->screen;
+ while(l->front != front){
+ f = l->front;
+ x = l->screenr;
+ overlap = rectclip(&x, f->layer->screenr);
+ if(overlap){
+ memlhide(f, x);
+ f->layer->clear = 0;
+ }
+ /* swap l and f in screen's list */
+ ff = f->layer->front;
+ rr = l->rear;
+ if(ff == nil)
+ s->frontmost = i;
+ else
+ ff->layer->rear = i;
+ if(rr == nil)
+ s->rearmost = f;
+ else
+ rr->layer->front = f;
+ l->front = ff;
+ l->rear = f;
+ f->layer->front = i;
+ f->layer->rear = rr;
+ if(overlap && fill)
+ memlexpose(i, x);
+ }
+}
+
+void
+_memltofrontfill(Memimage *i, int fill)
+{
+ _memltofront(i, nil, fill);
+ _memlsetclear(i->layer->screen);
+}
+
+void
+memltofront(Memimage *i)
+{
+ _memltofront(i, nil, 1);
+ _memlsetclear(i->layer->screen);
+}
+
+void
+memltofrontn(Memimage **ip, int n)
+{
+ Memimage *i, *front;
+ Memscreen *s;
+
+ if(n == 0)
+ return;
+ front = nil;
+ while(--n >= 0){
+ i = *ip++;
+ _memltofront(i, front, 1);
+ front = i;
+ }
+ s = front->layer->screen;
+ _memlsetclear(s);
+}
diff --git a/libmemlayer/ltorear.c b/libmemlayer/ltorear.c
new file mode 100644
index 00000000..44097613
--- /dev/null
+++ b/libmemlayer/ltorear.c
@@ -0,0 +1,68 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+void
+_memltorear(Memimage *i, Memimage *rear)
+{
+ Memlayer *l;
+ Memscreen *s;
+ Memimage *f, *r, *rr;
+ Rectangle x;
+ int overlap;
+
+ l = i->layer;
+ s = l->screen;
+ while(l->rear != rear){
+ r = l->rear;
+ x = l->screenr;
+ overlap = rectclip(&x, r->layer->screenr);
+ if(overlap){
+ memlhide(i, x);
+ l->clear = 0;
+ }
+ /* swap l and r in screen's list */
+ rr = r->layer->rear;
+ f = l->front;
+ if(rr == nil)
+ s->rearmost = i;
+ else
+ rr->layer->front = i;
+ if(f == nil)
+ s->frontmost = r;
+ else
+ f->layer->rear = r;
+ l->rear = rr;
+ l->front = r;
+ r->layer->rear = i;
+ r->layer->front = f;
+ if(overlap)
+ memlexpose(r, x);
+ }
+}
+
+void
+memltorear(Memimage *i)
+{
+ _memltorear(i, nil);
+ _memlsetclear(i->layer->screen);
+}
+
+void
+memltorearn(Memimage **ip, int n)
+{
+ Memimage *i, *rear;
+ Memscreen *s;
+
+ if(n == 0)
+ return;
+ rear = nil;
+ while(--n >= 0){
+ i = *ip++;
+ _memltorear(i, rear);
+ rear = i;
+ }
+ s = rear->layer->screen;
+ _memlsetclear(s);
+}
diff --git a/libmemlayer/mkfile b/libmemlayer/mkfile
new file mode 100644
index 00000000..0551a241
--- /dev/null
+++ b/libmemlayer/mkfile
@@ -0,0 +1,26 @@
+<../mkconfig
+
+LIB=libmemlayer.a
+
+COMMONFILES=\
+ draw.$O\
+ layerop.$O\
+ ldelete.$O\
+ lhide.$O\
+ line.$O\
+ load.$O\
+ lorigin.$O\
+ lsetrefresh.$O\
+ ltofront.$O\
+ ltorear.$O\
+ unload.$O\
+
+<mkfile-$SYSTARG #sets $SYSFILES based on OS architecture
+
+OFILES=$COMMONFILES $SYSFILES
+
+HFILES= $ROOT/include/draw.h\
+ $ROOT/include/memdraw.h\
+ $ROOT/include/memlayer.h
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
diff --git a/libmemlayer/mkfile-FreeBSD b/libmemlayer/mkfile-FreeBSD
new file mode 100644
index 00000000..d772cd4e
--- /dev/null
+++ b/libmemlayer/mkfile-FreeBSD
@@ -0,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
diff --git a/libmemlayer/mkfile-Hp b/libmemlayer/mkfile-Hp
new file mode 100644
index 00000000..d772cd4e
--- /dev/null
+++ b/libmemlayer/mkfile-Hp
@@ -0,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
diff --git a/libmemlayer/mkfile-Inferno b/libmemlayer/mkfile-Inferno
new file mode 100644
index 00000000..dec2d496
--- /dev/null
+++ b/libmemlayer/mkfile-Inferno
@@ -0,0 +1,4 @@
+#
+# System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
diff --git a/libmemlayer/mkfile-Irix b/libmemlayer/mkfile-Irix
new file mode 100644
index 00000000..d772cd4e
--- /dev/null
+++ b/libmemlayer/mkfile-Irix
@@ -0,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
diff --git a/libmemlayer/mkfile-Linux b/libmemlayer/mkfile-Linux
new file mode 100644
index 00000000..d772cd4e
--- /dev/null
+++ b/libmemlayer/mkfile-Linux
@@ -0,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
diff --git a/libmemlayer/mkfile-MacOSX b/libmemlayer/mkfile-MacOSX
new file mode 100644
index 00000000..d772cd4e
--- /dev/null
+++ b/libmemlayer/mkfile-MacOSX
@@ -0,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
diff --git a/libmemlayer/mkfile-NetBSD b/libmemlayer/mkfile-NetBSD
new file mode 100644
index 00000000..d772cd4e
--- /dev/null
+++ b/libmemlayer/mkfile-NetBSD
@@ -0,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
diff --git a/libmemlayer/mkfile-Nt b/libmemlayer/mkfile-Nt
new file mode 100644
index 00000000..bf823fcd
--- /dev/null
+++ b/libmemlayer/mkfile-Nt
@@ -0,0 +1,4 @@
+#
+# System dependent objects for Nt model systems
+#
+SYSFILES=lalloc.$O
diff --git a/libmemlayer/mkfile-Plan9 b/libmemlayer/mkfile-Plan9
new file mode 100644
index 00000000..dec2d496
--- /dev/null
+++ b/libmemlayer/mkfile-Plan9
@@ -0,0 +1,4 @@
+#
+# System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
diff --git a/libmemlayer/mkfile-Posix b/libmemlayer/mkfile-Posix
new file mode 100644
index 00000000..dec2d496
--- /dev/null
+++ b/libmemlayer/mkfile-Posix
@@ -0,0 +1,4 @@
+#
+# System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
diff --git a/libmemlayer/mkfile-Solaris b/libmemlayer/mkfile-Solaris
new file mode 100644
index 00000000..dec2d496
--- /dev/null
+++ b/libmemlayer/mkfile-Solaris
@@ -0,0 +1,4 @@
+#
+# System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
diff --git a/libmemlayer/mkfile-Unixware b/libmemlayer/mkfile-Unixware
new file mode 100644
index 00000000..d772cd4e
--- /dev/null
+++ b/libmemlayer/mkfile-Unixware
@@ -0,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
diff --git a/libmemlayer/mkfile-os b/libmemlayer/mkfile-os
new file mode 100644
index 00000000..dec2d496
--- /dev/null
+++ b/libmemlayer/mkfile-os
@@ -0,0 +1,4 @@
+#
+# System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
diff --git a/libmemlayer/unload.c b/libmemlayer/unload.c
new file mode 100644
index 00000000..741fe423
--- /dev/null
+++ b/libmemlayer/unload.c
@@ -0,0 +1,51 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+int
+memunload(Memimage *src, Rectangle r, uchar *data, int n)
+{
+ Memimage *tmp;
+ Memlayer *dl;
+ Rectangle lr;
+ int dx;
+
+ Top:
+ dl = src->layer;
+ if(dl == nil)
+ return unloadmemimage(src, r, data, n);
+
+ /*
+ * Convert to screen coordinates.
+ */
+ lr = r;
+ r.min.x += dl->delta.x;
+ r.min.y += dl->delta.y;
+ r.max.x += dl->delta.x;
+ r.max.y += dl->delta.y;
+ dx = dl->delta.x&(7/src->depth);
+ if(dl->clear && dx==0){
+ src = dl->screen->image;
+ goto Top;
+ }
+
+ /*
+ * src is an obscured layer or data is unaligned
+ */
+ if(dl->save && dx==0){
+ if(dl->refreshfn != nil)
+ return -1; /* can't unload window if it's not Refbackup */
+ if(n > 0)
+ memlhide(src, r);
+ n = unloadmemimage(dl->save, lr, data, n);
+ return n;
+ }
+ tmp = allocmemimage(lr, src->chan);
+ if(tmp == nil)
+ return -1;
+ memdraw(tmp, lr, src, lr.min, nil, lr.min, S);
+ n = unloadmemimage(tmp, lr, data, n);
+ freememimage(tmp);
+ return n;
+}