9fans.net/go@v0.0.5/draw/drawfcall/mux.go (about) 1 // +build !plan9 2 3 package drawfcall 4 5 import ( 6 "fmt" 7 "image" 8 "io" 9 "os" 10 "os/exec" 11 "sync" 12 ) 13 14 type Conn struct { 15 r sync.Mutex 16 rd io.ReadCloser 17 18 w sync.Mutex 19 wr io.WriteCloser 20 21 tag sync.Mutex 22 muxer bool 23 freetag map[byte]bool 24 tagmap map[byte]chan []byte 25 } 26 27 func New() (*Conn, error) { 28 devdraw := os.Getenv("DEVDRAW") 29 r1, w1, _ := os.Pipe() 30 r2, w2, _ := os.Pipe() 31 if devdraw == "" { 32 devdraw = "devdraw" 33 } 34 cmd := exec.Command(devdraw, os.Args[0], "(devdraw)") 35 cmd.Args[0] = os.Args[0] 36 cmd.Env = []string{"NOLIBTHREADDAEMONIZE=1"} 37 cmd.Env = append(cmd.Env, os.Environ()...) 38 cmd.Dir = "/" 39 cmd.Stdin = r1 40 cmd.Stdout = w2 41 cmd.Stderr = os.Stderr 42 err := cmd.Start() 43 r1.Close() 44 w2.Close() 45 if err != nil { 46 r2.Close() 47 w1.Close() 48 return nil, fmt.Errorf("drawfcall.New: %v", err) 49 } 50 51 c := &Conn{ 52 rd: r2, 53 wr: w1, 54 freetag: make(map[byte]bool), 55 tagmap: make(map[byte]chan []byte), 56 } 57 for i := 1; i <= 254; i++ { 58 c.freetag[byte(i)] = true 59 } 60 c.rd = r2 61 c.wr = w1 62 return c, nil 63 } 64 65 func (c *Conn) RPC(tx, rx *Msg) error { 66 msg := tx.Marshal() 67 ch := make(chan []byte, 1) 68 c.tag.Lock() 69 if len(c.freetag) == 0 { 70 c.tag.Unlock() 71 return fmt.Errorf("out of tags") 72 } 73 var tag byte 74 for tag = range c.freetag { 75 break 76 } 77 delete(c.freetag, tag) 78 c.tagmap[tag] = ch 79 if !c.muxer { 80 c.muxer = true 81 ch <- nil 82 } 83 c.tag.Unlock() 84 c.w.Lock() 85 msg[4] = tag 86 _, err := c.wr.Write(msg) 87 c.w.Unlock() 88 if err != nil { 89 return err 90 } 91 for msg = range ch { 92 if msg != nil { 93 break 94 } 95 msg, err = ReadMsg(c.rd) 96 if err != nil { 97 return err 98 } 99 c.tag.Lock() 100 tag := msg[4] 101 ch1 := c.tagmap[tag] 102 delete(c.tagmap, tag) 103 c.freetag[tag] = true 104 c.muxer = false 105 for _, ch2 := range c.tagmap { 106 c.muxer = true 107 ch2 <- nil 108 break 109 } 110 c.tag.Unlock() 111 ch1 <- msg 112 } 113 if err := rx.Unmarshal(msg); err != nil { 114 return err 115 } 116 if rx.Type == Rerror { 117 return fmt.Errorf("%s", rx.Error) 118 } 119 if rx.Type != tx.Type+1 { 120 return fmt.Errorf("type mismatch") 121 } 122 return nil 123 } 124 125 func (c *Conn) Close() error { 126 c.w.Lock() 127 err1 := c.wr.Close() 128 c.w.Unlock() 129 c.r.Lock() 130 err2 := c.rd.Close() 131 c.r.Unlock() 132 if err1 != nil { 133 return err1 134 } 135 return err2 136 } 137 138 func (c *Conn) Init(label, winsize string) error { 139 tx := &Msg{Type: Tinit, Label: label, Winsize: winsize} 140 rx := &Msg{} 141 return c.RPC(tx, rx) 142 } 143 144 func (c *Conn) ReadMouse() (m Mouse, resized bool, err error) { 145 tx := &Msg{Type: Trdmouse} 146 rx := &Msg{} 147 if err = c.RPC(tx, rx); err != nil { 148 return 149 } 150 m = rx.Mouse 151 resized = rx.Resized 152 return 153 } 154 155 func (c *Conn) ReadKbd() (r rune, err error) { 156 tx := &Msg{Type: Trdkbd} 157 rx := &Msg{} 158 if err = c.RPC(tx, rx); err != nil { 159 return 160 } 161 r = rx.Rune 162 return 163 } 164 165 func (c *Conn) MoveTo(p image.Point) error { 166 tx := &Msg{Type: Tmoveto, Mouse: Mouse{Point: p}} 167 rx := &Msg{} 168 return c.RPC(tx, rx) 169 } 170 171 func (c *Conn) Cursor(cursor *Cursor) error { 172 tx := &Msg{Type: Tcursor} 173 if cursor == nil { 174 tx.Arrow = true 175 } else { 176 tx.Cursor = *cursor 177 } 178 rx := &Msg{} 179 return c.RPC(tx, rx) 180 } 181 182 // copied from ../cursor.go to avoid import cycle 183 184 var expand = [16]uint8{ 185 0x00, 0x03, 0x0c, 0x0f, 186 0x30, 0x33, 0x3c, 0x3f, 187 0xc0, 0xc3, 0xcc, 0xcf, 188 0xf0, 0xf3, 0xfc, 0xff, 189 } 190 191 // scaleCursor returns a high-DPI version of c. 192 func scaleCursor(c Cursor) Cursor2 { 193 var c2 Cursor2 194 c2.X = 2 * c.X 195 c2.Y = 2 * c.Y 196 for y := 0; y < 16; y++ { 197 c2.White[8*y+4] = expand[c.White[2*y]>>4] 198 c2.White[8*y] = c2.White[8*y+4] 199 c2.Black[8*y+4] = expand[c.Black[2*y]>>4] 200 c2.Black[8*y] = c2.Black[8*y+4] 201 c2.White[8*y+5] = expand[c.White[2*y]&15] 202 c2.White[8*y+1] = c2.White[8*y+5] 203 c2.Black[8*y+5] = expand[c.Black[2*y]&15] 204 c2.Black[8*y+1] = c2.Black[8*y+5] 205 c2.White[8*y+6] = expand[c.White[2*y+1]>>4] 206 c2.White[8*y+2] = c2.White[8*y+6] 207 c2.Black[8*y+6] = expand[c.Black[2*y+1]>>4] 208 c2.Black[8*y+2] = c2.Black[8*y+6] 209 c2.White[8*y+7] = expand[c.White[2*y+1]&15] 210 c2.White[8*y+3] = c2.White[8*y+7] 211 c2.Black[8*y+7] = expand[c.Black[2*y+1]&15] 212 c2.Black[8*y+3] = c2.Black[8*y+7] 213 } 214 return c2 215 } 216 217 func (c *Conn) Cursor2(cursor *Cursor, cursor2 *Cursor2) error { 218 tx := &Msg{Type: Tcursor2} 219 if cursor == nil { 220 tx.Arrow = true 221 } else { 222 tx.Cursor = *cursor 223 if cursor2 == nil { 224 tx.Cursor2 = scaleCursor(*cursor) 225 } else { 226 tx.Cursor2 = *cursor2 227 } 228 } 229 rx := &Msg{} 230 return c.RPC(tx, rx) 231 } 232 233 func (c *Conn) BounceMouse(m *Mouse) error { 234 tx := &Msg{Type: Tbouncemouse, Mouse: *m} 235 rx := &Msg{} 236 return c.RPC(tx, rx) 237 } 238 239 func (c *Conn) Label(label string) error { 240 tx := &Msg{Type: Tlabel, Label: label} 241 rx := &Msg{} 242 return c.RPC(tx, rx) 243 } 244 245 // Return values are bytes copied, actual size, error. 246 func (c *Conn) ReadSnarf(b []byte) (int, int, error) { 247 tx := &Msg{Type: Trdsnarf} 248 rx := &Msg{} 249 if err := c.RPC(tx, rx); err != nil { 250 return 0, 0, err 251 } 252 n := copy(b, rx.Snarf) 253 if n < len(rx.Snarf) { 254 return 0, len(rx.Snarf), nil 255 } 256 return n, n, nil 257 } 258 259 func (c *Conn) WriteSnarf(snarf []byte) error { 260 tx := &Msg{Type: Twrsnarf, Snarf: snarf} 261 rx := &Msg{} 262 return c.RPC(tx, rx) 263 } 264 265 func (c *Conn) Top() error { 266 tx := &Msg{Type: Ttop} 267 rx := &Msg{} 268 return c.RPC(tx, rx) 269 } 270 271 func (c *Conn) Resize(r image.Rectangle) error { 272 tx := &Msg{Type: Tresize, Rect: r} 273 rx := &Msg{} 274 return c.RPC(tx, rx) 275 } 276 277 func (c *Conn) ReadDraw(b []byte) (int, error) { 278 tx := &Msg{Type: Trddraw, Count: len(b)} 279 rx := &Msg{} 280 if err := c.RPC(tx, rx); err != nil { 281 return 0, err 282 } 283 copy(b, rx.Data) 284 return len(rx.Data), nil 285 } 286 287 func (c *Conn) WriteDraw(b []byte) (int, error) { 288 tx := &Msg{Type: Twrdraw, Data: b} 289 rx := &Msg{} 290 if err := c.RPC(tx, rx); err != nil { 291 return 0, err 292 } 293 return rx.Count, nil 294 }