```go ```go type Area struct { // implements Control // Paint receives requests to redraw from the window system. Paint chan PaintRequest // Keyboard receives keyboard events. Key chan KeyEvent // not covered here // Mouse receives mouse events. Mouse chan MouseEvent // not covered here } // PaintRequest represents a request to redraw an Area. // It is sent across Area.Paint. type PaintRequest struct { // Rect is the clipping rectangle that needs redraw. Rect image.Rect // Out is a channel on which you send the image to redraw. Out chan<- *image.NRGBA } ``` and an example of intended use: ```go func myAreaGoroutine(area *ui.Area, start <-chan bool) { var img *image.NRGBA // initialize img here <-start // sent after calling Window.Open() area.SetSize(img.Rect.Dx(), img.Rect.Dy()) // sets the internal size; scrollbars and scrolling is handled automatically for { select { case req := <-area.Paint: req.Out <- img.SubImage(req.Rect).(*image.NRGBA) case e := <-area.Mouse: // draw on a mouse click, for instance } } } ``` ## Windows TODO ## GTK+ We can use `GtkDrawingArea`. We hook into the `draw` signal; it does something equivalent to ```go func draw_callback(widget *C.GtkWidget, cr *C.cairo_t, data C.gpointer) C.gboolean { s := (*sysData)(unsafe.Pointer(data)) // TODO get clip rectangle that needs drawing imgret := make(chan *image.NRGBA) defer close(imgret) s.paint <- PaintRequest{ Rect: /* clip rect */, Out: imgret, } i := <-imgret pixbuf := C.gdk_pixbuf_new_from_data( (*C.guchar)(unsafe.Pointer(&i.Pix[0])), C.GDK_COLORSPACE_RGB, C.TRUE, // has alpha channel 8, // bits per sample C.int(i.Rect.Dx()), C.int(i.Rect.Dy()), C.int(i.Stride), nil, nil) // do not free data C.gdk_cairo_set_source_pixbuf(cr, pixbuf, /* x of clip rect */, /* y of clip rect */) return C.FALSE // TODO what does this return value mean? docs don't say } ``` TODO figure out how scrolling plays into this ## Cocoa TODO