/* * 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 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.op = op; d.mask = mask; _memlayerop(ldrawop, dst, r, r, &d); }