9fans.net/go@v0.0.7/cmd/devdraw/srv.go (about) 1 /* 2 * Window system protocol server. 3 */ 4 5 package main 6 7 import ( 8 "flag" 9 "fmt" 10 "io" 11 "log" 12 "os" 13 "strconv" 14 "time" 15 16 "9fans.net/go/draw" 17 "9fans.net/go/draw/drawfcall" 18 "9fans.net/go/draw/memdraw" 19 ) 20 21 var client0 *Client 22 23 var trace int = 0 24 var srvname string 25 var afd int 26 var adir string 27 28 func usage() { 29 fmt.Fprintf(os.Stderr, "usage: devdraw (don't run directly)\n") 30 os.Exit(2) 31 } 32 33 func main() { 34 log.SetPrefix("devdraw: ") 35 log.SetFlags(0) 36 37 flag.BoolVar(new(bool), "D", false, "ignored") 38 flag.BoolVar(new(bool), "f", false, "ignored") 39 flag.BoolVar(new(bool), "g", false, "ignored") 40 flag.BoolVar(new(bool), "b", false, "ignored") 41 flag.StringVar(&srvname, "s", srvname, "service name") 42 flag.Usage = usage 43 flag.Parse() 44 45 memdraw.Init() 46 p := os.Getenv("DEVDRAWTRACE") 47 if p != "" { 48 trace, _ = strconv.Atoi(p) 49 } 50 51 if srvname == "" { 52 client0 = new(Client) 53 client0.displaydpi = 100 54 55 /* 56 * Move the protocol off stdin/stdout so that 57 * any inadvertent prints don't screw things up. 58 */ 59 client0.rfd = os.Stdin 60 client0.wfd = os.Stdout 61 os.Stdin, _ = os.Open("/dev/null") 62 os.Stdout, _ = os.Create("/dev/null") 63 } 64 65 gfx_main() 66 } 67 68 func gfx_started() { 69 if srvname == "" { 70 // Legacy mode: serving single client on pipes. 71 go serveproc(client0) 72 return 73 } 74 75 panic("server mode") 76 /* 77 // Server mode. 78 ns := getns() 79 if ns == nil { 80 sysfatal("out of memory") 81 } 82 83 addr := fmt.Sprintf("unix!%s/%s", ns, srvname) 84 free(ns) 85 if addr == nil { 86 sysfatal("out of memory") 87 } 88 89 afd = announce(addr, adir) 90 if afd < 0 { 91 sysfatal("announce %s: %r", addr) 92 } 93 94 go listenproc() 95 */ 96 } 97 98 /* 99 func listenproc() { 100 for { 101 var dir string 102 fd := listen(adir, dir) 103 if fd < 0 { 104 sysfatal("listen: %r") 105 } 106 c := new(Client) 107 if c == nil { 108 fmt.Fprintf(os.Stderr, "initdraw: allocating client0: out of memory") 109 abort() 110 } 111 c.displaydpi = 100 112 c.rfd = fd 113 c.wfd = fd 114 go serveproc(c) 115 } 116 } 117 */ 118 119 func serveproc(c *Client) { 120 for { 121 b, err := drawfcall.ReadMsg(c.rfd) 122 if err != nil { 123 if err != io.EOF { 124 fmt.Fprintf(os.Stderr, "serveproc: cannot read message: %v\n", err) 125 } 126 break 127 } 128 129 var m drawfcall.Msg 130 if err := m.Unmarshal(b); err != nil { 131 fmt.Fprintf(os.Stderr, "serveproc: cannot convert message: %v\n", err) 132 break 133 } 134 if trace != 0 { 135 log.Printf("%v <- %v\n", time.Now().UnixNano()/1000000, &m) 136 } 137 runmsg(c, &m) 138 } 139 140 if c == client0 { 141 rpc_shutdown() 142 os.Exit(0) 143 } 144 } 145 146 func replyerror(c *Client, m *drawfcall.Msg, err error) { 147 m.Type = drawfcall.Rerror 148 m.Error = err.Error() 149 replymsg(c, m) 150 } 151 152 /* 153 * Handle a single wsysmsg. 154 * Might queue for later (kbd, mouse read) 155 */ 156 var runmsg_buf [65536]byte 157 158 func runmsg(c *Client, m *drawfcall.Msg) { 159 switch m.Type { 160 case drawfcall.Tctxt: 161 c.wsysid = m.ID 162 replymsg(c, m) 163 164 case drawfcall.Tinit: 165 i, err := rpc_attach(c, m.Label, m.Winsize) 166 if err != nil { 167 replyerror(c, m, err) 168 break 169 } 170 // println("I", i) 171 draw_initdisplaymemimage(c, i) 172 replymsg(c, m) 173 174 case drawfcall.Trdmouse: 175 c.eventlk.Lock() 176 if (c.mousetags.wi+1)%len(c.mousetags.t) == c.mousetags.ri { 177 c.eventlk.Unlock() 178 replyerror(c, m, fmt.Errorf("too many queued mouse reads")) 179 break 180 } 181 c.mousetags.t[c.mousetags.wi] = int(m.Tag) 182 c.mousetags.wi++ 183 if c.mousetags.wi == len(c.mousetags.t) { 184 c.mousetags.wi = 0 185 } 186 c.mouse.stall = 0 187 matchmouse(c) 188 c.eventlk.Unlock() 189 190 case drawfcall.Trdkbd, drawfcall.Trdkbd4: 191 c.eventlk.Lock() 192 if (c.kbdtags.wi+1)%len(c.kbdtags.t) == c.kbdtags.ri { 193 c.eventlk.Unlock() 194 replyerror(c, m, fmt.Errorf("too many queued keyboard reads")) 195 break 196 } 197 ext := 0 198 if m.Type == drawfcall.Trdkbd4 { 199 ext = 1 200 } 201 c.kbdtags.t[c.kbdtags.wi] = int(m.Tag)<<1 | ext 202 c.kbdtags.wi++ 203 if c.kbdtags.wi == len(c.kbdtags.t) { 204 c.kbdtags.wi = 0 205 } 206 c.kbd.stall = 0 207 matchkbd(c) 208 c.eventlk.Unlock() 209 210 case drawfcall.Tmoveto: 211 c.impl.rpc_setmouse(c, m.Mouse.Point) 212 replymsg(c, m) 213 214 case drawfcall.Tcursor: 215 if m.Arrow { 216 c.impl.rpc_setcursor(c, nil, nil) 217 } else { 218 cur := (*draw.Cursor)(&m.Cursor) 219 cur2 := (*draw.Cursor2)(&m.Cursor2) 220 *cur2 = draw.ScaleCursor(*cur) 221 c.impl.rpc_setcursor(c, cur, cur2) 222 } 223 replymsg(c, m) 224 225 case drawfcall.Tcursor2: 226 if m.Arrow { 227 c.impl.rpc_setcursor(c, nil, nil) 228 } else { 229 c.impl.rpc_setcursor(c, (*draw.Cursor)(&m.Cursor), (*draw.Cursor2)(&m.Cursor2)) 230 } 231 replymsg(c, m) 232 233 case drawfcall.Tbouncemouse: 234 c.impl.rpc_bouncemouse(c, draw.Mouse(m.Mouse)) 235 replymsg(c, m) 236 237 case drawfcall.Tlabel: 238 c.impl.rpc_setlabel(c, m.Label) 239 replymsg(c, m) 240 241 case drawfcall.Trdsnarf: 242 m.Snarf = rpc_getsnarf() 243 replymsg(c, m) 244 m.Snarf = nil 245 246 case drawfcall.Twrsnarf: 247 rpc_putsnarf(m.Snarf) 248 replymsg(c, m) 249 250 case drawfcall.Trddraw: 251 n := m.Count 252 if n > len(runmsg_buf) { 253 n = len(runmsg_buf) 254 } 255 n, err := draw_dataread(c, runmsg_buf[:n]) 256 if err != nil { 257 replyerror(c, m, err) 258 } else { 259 m.Count = n 260 m.Data = runmsg_buf[:n] 261 replymsg(c, m) 262 } 263 264 case drawfcall.Twrdraw: 265 if _, err := draw_datawrite(c, m.Data); err != nil { 266 replyerror(c, m, err) 267 } else { 268 m.Count = len(m.Data) 269 replymsg(c, m) 270 } 271 272 case drawfcall.Ttop: 273 c.impl.rpc_topwin(c) 274 replymsg(c, m) 275 276 case drawfcall.Tresize: 277 c.impl.rpc_resizewindow(c, m.Rect) 278 replymsg(c, m) 279 } 280 } 281 282 /* 283 * drawfcall.Reply to m. 284 */ 285 func replymsg(c *Client, m *drawfcall.Msg) { 286 /* T -> R msg */ 287 if m.Type%2 == 0 { 288 m.Type++ 289 } 290 291 if trace != 0 { 292 fmt.Fprintf(os.Stderr, "%d -> %v\n", time.Now().UnixNano()/1000000, m) 293 } 294 295 c.wfdlk.Lock() 296 if _, err := c.wfd.Write(m.Marshal()); err != nil { 297 fmt.Fprintf(os.Stderr, "client write: %v\n", err) 298 } 299 c.wfdlk.Unlock() 300 } 301 302 /* 303 * Match queued kbd reads with queued kbd characters. 304 */ 305 func matchkbd(c *Client) { 306 if c.kbd.stall != 0 { 307 return 308 } 309 for c.kbd.ri != c.kbd.wi && c.kbdtags.ri != c.kbdtags.wi { 310 tag := c.kbdtags.t[c.kbdtags.ri] 311 c.kbdtags.ri++ 312 var m drawfcall.Msg 313 m.Type = drawfcall.Rrdkbd 314 if tag&1 != 0 { 315 m.Type = drawfcall.Rrdkbd4 316 } 317 m.Tag = uint8(tag >> 1) 318 if c.kbdtags.ri == len(c.kbdtags.t) { 319 c.kbdtags.ri = 0 320 } 321 m.Rune = c.kbd.r[c.kbd.ri] 322 c.kbd.ri++ 323 if c.kbd.ri == len(c.kbd.r) { 324 c.kbd.ri = 0 325 } 326 replymsg(c, &m) 327 } 328 } 329 330 // matchmouse matches queued mouse reads with queued mouse events. 331 // It must be called with c->eventlk held. 332 func matchmouse(c *Client) { 333 for c.mouse.ri != c.mouse.wi && c.mousetags.ri != c.mousetags.wi { 334 var m drawfcall.Msg 335 m.Type = drawfcall.Rrdmouse 336 m.Tag = uint8(c.mousetags.t[c.mousetags.ri]) 337 c.mousetags.ri++ 338 if c.mousetags.ri == len(c.mousetags.t) { 339 c.mousetags.ri = 0 340 } 341 m.Mouse = drawfcall.Mouse(c.mouse.m[c.mouse.ri]) 342 m.Resized = c.mouse.resized 343 c.mouse.resized = false 344 /* 345 if(m.resized) 346 fmt.Fprintf(os.Stderr, "sending resize\n"); 347 */ 348 c.mouse.ri++ 349 if c.mouse.ri == len(c.mouse.m) { 350 c.mouse.ri = 0 351 } 352 replymsg(c, &m) 353 } 354 } 355 356 func gfx_mouseresized(c *Client) { 357 gfx_mousetrack(c, -1, -1, -1, ^uint32(0)) 358 } 359 360 func gfx_mousetrack(c *Client, x int, y int, b int, ms uint32) { 361 c.eventlk.Lock() 362 if x == -1 && y == -1 && b == -1 && ms == ^uint32(0) { 363 var copy *draw.Mouse 364 // repeat last mouse event for resize 365 if c.mouse.ri == 0 { 366 copy = &c.mouse.m[len(c.mouse.m)-1] 367 } else { 368 copy = &c.mouse.m[c.mouse.ri-1] 369 } 370 x = copy.Point.X 371 y = copy.Point.Y 372 b = copy.Buttons 373 ms = copy.Msec 374 c.mouse.resized = true 375 } 376 if x < c.mouserect.Min.X { 377 x = c.mouserect.Min.X 378 } 379 if x > c.mouserect.Max.X { 380 x = c.mouserect.Max.X 381 } 382 if y < c.mouserect.Min.Y { 383 y = c.mouserect.Min.Y 384 } 385 if y > c.mouserect.Max.Y { 386 y = c.mouserect.Max.Y 387 } 388 389 // If reader has stopped reading, don't bother. 390 // If reader is completely caught up, definitely queue. 391 // Otherwise, queue only button change events. 392 if c.mouse.stall == 0 { 393 if c.mouse.wi == c.mouse.ri || c.mouse.last.Buttons != b { 394 m := &c.mouse.last 395 m.Point.X = x 396 m.Point.Y = y 397 m.Buttons = b 398 m.Msec = ms 399 400 c.mouse.m[c.mouse.wi] = *m 401 c.mouse.wi++ 402 if c.mouse.wi == len(c.mouse.m) { 403 c.mouse.wi = 0 404 } 405 if c.mouse.wi == c.mouse.ri { 406 c.mouse.stall = 1 407 c.mouse.ri = 0 408 c.mouse.wi = 1 409 c.mouse.m[0] = *m 410 } 411 matchmouse(c) 412 } 413 } 414 c.eventlk.Unlock() 415 } 416 417 // kputc adds ch to the keyboard buffer. 418 // It must be called with c->eventlk held. 419 func kputc(c *Client, ch rune) { 420 c.kbd.r[c.kbd.wi] = ch 421 c.kbd.wi++ 422 if c.kbd.wi == len(c.kbd.r) { 423 c.kbd.wi = 0 424 } 425 if c.kbd.ri == c.kbd.wi { 426 c.kbd.stall = 1 427 } 428 matchkbd(c) 429 } 430 431 // gfx_abortcompose stops any pending compose sequence, 432 // because a mouse button has been clicked. 433 // It is called from the graphics thread with no locks held. 434 func gfx_abortcompose(c *Client) { 435 c.eventlk.Lock() 436 if c.kbd.alting { 437 c.kbd.alting = false 438 c.kbd.nk = 0 439 } 440 c.eventlk.Unlock() 441 } 442 443 // gfx_keystroke records a single-rune keystroke. 444 // It is called from the graphics thread with no locks held. 445 func gfx_keystroke(c *Client, ch rune) { 446 c.eventlk.Lock() 447 if ch == draw.KeyAlt { 448 c.kbd.alting = !c.kbd.alting 449 c.kbd.nk = 0 450 c.eventlk.Unlock() 451 return 452 } 453 if ch == draw.KeyCmd+'r' { 454 if c.forcedpi != 0 { 455 c.forcedpi = 0 456 } else if c.displaydpi >= 200 { 457 c.forcedpi = 100 458 } else { 459 c.forcedpi = 225 460 } 461 c.eventlk.Unlock() 462 c.impl.rpc_resizeimg(c) 463 return 464 } 465 if !c.kbd.alting { 466 kputc(c, ch) 467 c.eventlk.Unlock() 468 return 469 } 470 if c.kbd.nk >= len(c.kbd.k) { // should not happen 471 c.kbd.nk = 0 472 } 473 c.kbd.k[c.kbd.nk] = ch 474 c.kbd.nk++ 475 ch = toLatin1(c.kbd.k[:c.kbd.nk]) 476 if ch > 0 { 477 c.kbd.alting = false 478 kputc(c, ch) 479 c.kbd.nk = 0 480 c.eventlk.Unlock() 481 return 482 } 483 if ch == -1 { 484 c.kbd.alting = false 485 for i := 0; i < c.kbd.nk; i++ { 486 kputc(c, c.kbd.k[i]) 487 } 488 c.kbd.nk = 0 489 c.eventlk.Unlock() 490 return 491 } 492 // need more input 493 c.eventlk.Unlock() 494 return 495 }