9fans.net/go@v0.0.5/draw/drawfcall/mux_plan9.go (about) 1 package drawfcall 2 3 import ( 4 "bufio" 5 "bytes" 6 "encoding/binary" 7 "errors" 8 "fmt" 9 "image" 10 "io/ioutil" 11 "os" 12 "strconv" 13 "strings" 14 "sync" 15 ) 16 17 type Conn struct { 18 ctl *os.File 19 data *os.File 20 cons *bufio.Reader 21 consctl *os.File 22 mouse *os.File 23 snarf *os.File 24 cursor *os.File 25 n int // connection number 26 initCtl []byte 27 oldLabel string 28 29 readData []byte 30 ctlWasRead bool 31 lk sync.Mutex 32 } 33 34 func New() (*Conn, error) { 35 ctl, err := os.OpenFile("/dev/draw/new", os.O_RDWR, 0) 36 if err != nil { 37 return nil, err 38 } 39 40 var b [12*12 + 1]byte 41 nr, err := ctl.Read(b[:]) 42 if err != nil { 43 return nil, err 44 } 45 f := strings.Fields(string(b[:nr])) 46 if len(f) != 12 { 47 return nil, fmt.Errorf("bad ctl file") 48 } 49 n, err := strconv.Atoi(f[0]) 50 if err != nil { 51 return nil, err 52 } 53 54 data, err := os.OpenFile(fmt.Sprintf("/dev/draw/%v/data", n), os.O_RDWR, 0) 55 if err != nil { 56 return nil, err 57 } 58 cons, err := os.Open("/dev/cons") 59 if err != nil { 60 return nil, err 61 } 62 63 consctl, err := os.OpenFile("/dev/consctl", os.O_WRONLY, 0) 64 if err != nil { 65 return nil, err 66 } 67 _, err = consctl.WriteString("rawon") 68 if err != nil { 69 return nil, err 70 } 71 72 mouse, err := os.OpenFile("/dev/mouse", os.O_RDWR, 0) 73 if err != nil { 74 return nil, err 75 } 76 snarf, err := os.Open("/dev/snarf") 77 if err != nil { 78 return nil, err 79 } 80 cursor, err := os.OpenFile("/dev/cursor", os.O_WRONLY, 0) 81 if err != nil { 82 return nil, err 83 } 84 85 return &Conn{ 86 ctl: ctl, 87 data: data, 88 cons: bufio.NewReader(cons), 89 consctl: consctl, 90 mouse: mouse, 91 snarf: snarf, 92 cursor: cursor, 93 initCtl: b[:nr], 94 n: n, 95 }, nil 96 } 97 98 func (c *Conn) Close() error { 99 return c.ctl.Close() 100 } 101 102 func (c *Conn) Init(label, winsize string) error { 103 if b, err := ioutil.ReadFile("/dev/label"); err == nil { 104 c.oldLabel = string(b) 105 } 106 // Ignore error because we may not be running in rio 107 ioutil.WriteFile("/dev/label", []byte(label), 0600) 108 return nil 109 } 110 111 func atoi(s string) (n int) { 112 n, _ = strconv.Atoi(s) 113 return 114 } 115 116 func (c *Conn) ReadMouse() (m Mouse, resized bool, err error) { 117 var buf [1 + 5*12]byte 118 var nr int 119 120 nr, err = c.mouse.Read(buf[:]) 121 if err != nil { 122 return 123 } 124 f := strings.Fields(string(buf[:nr])) 125 if len(f) != 5 { 126 err = errors.New("bad mouse event") 127 return 128 } 129 m.Point = image.Pt(atoi(f[1]), atoi(f[2])) 130 m.Buttons = atoi(f[3]) 131 m.Msec = atoi(f[4]) 132 if f[0] == "r" { 133 resized = true 134 } 135 return 136 } 137 138 func (c *Conn) ReadKbd() (r rune, err error) { 139 r, _, err = c.cons.ReadRune() 140 return 141 } 142 143 func (c *Conn) MoveTo(p image.Point) error { 144 _, err := fmt.Fprintf(c.mouse, "m%11d %11d ", p.X, p.Y) 145 return err 146 } 147 148 func (c *Conn) Cursor(cursor *Cursor) error { 149 if cursor == nil { 150 // Revert to default cursor (Arrow) 151 _, err := c.cursor.Write([]byte{0}) 152 return err 153 } 154 b := make([]byte, 2*4+len(cursor.Clr)+len(cursor.Set)) 155 i := 0 156 binary.LittleEndian.PutUint32(b[i:], uint32(cursor.Point.X)) 157 i += 4 158 binary.LittleEndian.PutUint32(b[i:], uint32(cursor.Point.Y)) 159 i += 4 160 i += copy(b[i:], cursor.Clr[:]) 161 i += copy(b[i:], cursor.Set[:]) 162 _, err := c.cursor.Write(b) 163 return err 164 } 165 166 func (c *Conn) BounceMouse(m *Mouse) error { 167 panic("unimplemented") 168 } 169 170 func (c *Conn) Label(label string) error { 171 panic("unimplemented") 172 } 173 174 // Return values are bytes copied, actual size, error. 175 func (c *Conn) ReadSnarf(b []byte) (int, int, error) { 176 _, err := c.snarf.Seek(0, 0) 177 if err != nil { 178 return 0, 0, err 179 } 180 n, err := c.snarf.Read(b) 181 return n, n, err 182 } 183 184 func (c *Conn) WriteSnarf(snarf []byte) error { 185 // /dev/snarf updates when the file is closed, so we must open it for each call 186 f, err := os.OpenFile("/dev/snarf", os.O_WRONLY, 0) 187 if err != nil { 188 return err 189 } 190 _, err = f.Write(snarf) 191 if err != nil { 192 return err 193 } 194 return f.Close() 195 } 196 197 func (c *Conn) Top() error { 198 panic("unimplemented") 199 } 200 201 func (c *Conn) Resize(r image.Rectangle) error { 202 panic("unimplemented") 203 } 204 205 func (c *Conn) ReadDraw(b []byte) (n int, err error) { 206 c.lk.Lock() 207 if len(c.readData) > 0 { 208 n = copy(b, c.readData) 209 c.readData = c.readData[n:] 210 c.lk.Unlock() 211 return n, nil 212 } 213 c.lk.Unlock() 214 return c.data.Read(b[:]) 215 } 216 217 func bplong(b []byte, n uint32) { 218 binary.LittleEndian.PutUint32(b, n) 219 } 220 221 func (c *Conn) WriteDraw(b []byte) (int, error) { 222 i := 0 223 Loop: 224 for i < len(b) { 225 switch b[i] { 226 case 'J': // set image 0 to screen image 227 i++ 228 229 case 'I': // get image info: 'I' 230 c.lk.Lock() 231 if !c.ctlWasRead { 232 c.readData = append(c.readData, c.initCtl...) 233 c.ctlWasRead = true 234 } else { 235 b := make([]byte, 12*12) 236 n, err := c.ctl.Read(b) 237 if err != nil { 238 c.lk.Unlock() 239 return 0, err 240 } 241 c.readData = append(c.readData, b[:n]...) 242 } 243 c.lk.Unlock() 244 i++ 245 246 case 'q': // query: 'Q' n[1] queryspec[n] 247 if bytes.Equal(b, []byte{'q', 1, 'd'}) { 248 dpi := fmt.Sprintf("%12d", 100) 249 c.lk.Lock() 250 c.readData = append(c.readData, []byte(dpi)...) 251 c.lk.Unlock() 252 } 253 i += 1 + 1 + int(b[1]) 254 255 default: 256 break Loop 257 } 258 } 259 if len(b[i:]) == 0 { 260 return i, nil 261 } 262 n, err := c.data.Write(b[i:]) 263 return n + i, err 264 }