149 lines · 3.4 KB · Go
RawDownload
package draw import (	"fmt"	"image"	"runtime") // AllocImage allocates a new Image on display d. The arguments are:// - the rectangle representing the size// - the pixel descriptor: RGBA32 etc.// - whether the image is to be replicated (tiled)// - the starting background color for the imagefunc (d *Display) AllocImage(r image.Rectangle, pix Pix, repl bool, val Color) (*Image, error) {	d.mu.Lock()	defer d.mu.Unlock()	return allocImage(d, nil, r, pix, repl, val, 0, 0)} func (d *Display) allocImage(r image.Rectangle, pix Pix, repl bool, val Color) (i *Image, err error) {	return allocImage(d, nil, r, pix, repl, val, 0, 0)} func allocImage(d *Display, ai *Image, r image.Rectangle, pix Pix, repl bool, val Color, screenid uint32, refresh int) (i *Image, err error) {	defer func() {		if err != nil {			err = fmt.Errorf("allocimage %v %v: %v", r, pix, err)			i.free()			i = nil		}	}() 	depth := pix.Depth()	if depth == 0 {		err = fmt.Errorf("bad channel descriptor")		return	} 	// flush pending data so we don't get error allocating the image	d.flush(false)	a := d.bufimage(1 + 4 + 4 + 1 + 4 + 1 + 4*4 + 4*4 + 4)	d.imageid++	id := d.imageid	a[0] = 'b'	bplong(a[1:], id)	bplong(a[5:], screenid)	a[9] = byte(refresh)	bplong(a[10:], uint32(pix))	if repl {		a[14] = 1	} else {		a[14] = 0	}	bplong(a[15:], uint32(r.Min.X))	bplong(a[19:], uint32(r.Min.Y))	bplong(a[23:], uint32(r.Max.X))	bplong(a[27:], uint32(r.Max.Y))	clipr := r	if repl {		// huge but not infinite, so various offsets will leave it huge, not overflow		clipr = image.Rect(-0x3FFFFFFF, -0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF)	}	bplong(a[31:], uint32(clipr.Min.X))	bplong(a[35:], uint32(clipr.Min.Y))	bplong(a[39:], uint32(clipr.Max.X))	bplong(a[43:], uint32(clipr.Max.Y))	bplong(a[47:], uint32(val))	if err = d.flush(false); err != nil {		return	} 	i = ai	if i == nil {		i = new(Image)	}	*i = Image{		Display: d,		id:      id,		Pix:     pix,		Depth:   pix.Depth(),		R:       r,		Clipr:   clipr,		Repl:    repl,	}	runtime.SetFinalizer(i, (*Image).Free)	return i, nil} /*func namedimage(d *Display, name string) (*Image, nil) {	panic("namedimage")} func nameimage(i *Image, name string, in bool) error {	a := i.Display.bufimage(1+4+1+1+len(name))	a[0] = 'N'	bplong(a[1:], i.ID)	if in {		a[5] = 1	}	a[6] = len(name)	copy(a[7:], name)	return d.flushimage(false)}*/ func (i *Image) free() error {	if i == nil || i.Display == nil {		return nil	}	// make sure no refresh events occur on this if we block in the write	d := i.Display	// flush pending data so we don't get error deleting the image	d.flush(false)	a := d.bufimage(1 + 4)	a[0] = 'f'	bplong(a[1:], i.id)	if i.Screen != nil {		w := d.Windows		if w == i {			d.Windows = i.next		} else {			for ; w != nil; w = w.next {				if w.next == i {					w.next = i.next					break				}			}		}	}	i.Display = nil // So a second free (perhaps through a Finalizer) will be OK.	runtime.SetFinalizer(i, nil)	return d.flush(i.Screen != nil)} // Free frees the server resources for the image. Images have a finalizer that// calls Free automatically, if necessary, for garbage collected Images, but it// is more efficient to be explicit.func (i *Image) Free() error {	if i == nil {		return nil	}	if i.Display != nil && i == i.Display.ScreenImage {		panic("freeimage of ScreenImage")	}	i.Display.mu.Lock()	defer i.Display.mu.Unlock()	return i.free()}