package draw import ( "fmt" "os" "strconv" "strings" ) // NamedImage looks up an image the window system published by name and // installs it under a fresh id of ours. The 'n' message also sets the // client's infoid, so the image's geometry comes back from a plain read of // the ctl file -- the same 12-field block that draw/new returns. func (d *Display) NamedImage(name string) (*Image, error) { if name == "" || len(name) >= 256 { return nil, fmt.Errorf("namedimage: bad name %q", name) } d.mu.Lock() d.nextid++ id := d.nextid d.mu.Unlock() b := make([]byte, 6+len(name)) b[0] = 'n' put32(b, 1, id) b[5] = byte(len(name)) copy(b[6:], name) if err := d.write(b); err != nil { return nil, fmt.Errorf("namedimage %q: %w", name, err) } var info [12 * 12]byte n, err := d.ctl.ReadAt(info[:], 0) if err != nil && n < len(info) { return nil, fmt.Errorf("namedimage %q: ctl read: %w", name, err) } fld := func(i int) int32 { v, _ := strconv.Atoi(trim(string(info[i*12 : i*12+12]))) return int32(v) } return &Image{ d: d, id: id, chn: strToChan(trim(string(info[2*12 : 3*12]))), repl: fld(3) != 0, R: Rect(fld(4), fld(5), fld(6), fld(7)), Clipr: Rect(fld(8), fld(9), fld(10), fld(11)), }, nil } // Window returns the image to draw into: the rio window named by // /winname if there is one, otherwise the raw screen. // // Without this a program draws to image 0 -- the screen itself -- straight // over the window system. Nothing stops it: /dev/draw is the kernel's // device, not rio's, and rio publishes the window by name rather than // proxying the device. Being a good citizen is opt-in, and this is the // opt-in. func (d *Display) Window(dev string) (*Image, error) { if dev == "" { dev = "/dev" } buf, err := os.ReadFile(dev + "/winname") if err != nil { return d.Screen, nil // not under a window system } name := strings.TrimRight(string(buf), "\x00\n ") if name == "" { return d.Screen, nil } win, err := d.NamedImage(name) if err != nil { return nil, err } return win, nil } // Reattach re-reads winname and looks the window up again. rio replaces the // window's image on resize rather than resizing it in place, so a resize // event means "throw the old one away and ask again". func (d *Display) Reattach(dev string, old *Image) (*Image, error) { if old != nil && old.id != 0 { old.Free() // ignore errors: the old image may already be gone } return d.Window(dev) }