9fans.net/go@v0.0.5/draw/mouse.go (about) 1 package draw 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 8 "9fans.net/go/draw/drawfcall" 9 ) 10 11 // Mouse is the structure describing the current state of the mouse. 12 type Mouse struct { 13 Point // Location. 14 Buttons int // Buttons; bit 0 is button 1, bit 1 is button 2, etc. 15 Msec uint32 // Time stamp in milliseconds. 16 } 17 18 // Mousectl holds the interface to receive mouse events. 19 // 20 // This Go library differs from the Plan 9 C library in its updating 21 // of Mouse. Updating the Mouse field is the duty of every 22 // receiver from C. The Read method does the update, but any use 23 // of C in a select needs to update the field as well, as in: 24 // 25 // case mc.Mouse <- mc.C: 26 // 27 // In the Plan 9 C library, the sender does the write after the send, 28 // but that write could not be relied upon due to scheduling delays, 29 // so receivers conventionally also did the write, as above. 30 // This write-write race, while harmless, impedes using the race detector 31 // to find more serious races, and it is easily avoided: 32 // the receiver is now in charge of updating Mouse. 33 type Mousectl struct { 34 Mouse // Store Mouse events here. 35 C <-chan Mouse // Channel of Mouse events. 36 Resize <-chan bool // Each received value signals a window resize (see the display.Attach method). 37 Display *Display // The associated display. 38 } 39 40 // InitMouse connects to the mouse and returns a Mousectl to interact with it. 41 func (d *Display) InitMouse() *Mousectl { 42 ch := make(chan Mouse, 0) 43 rch := make(chan bool, 2) 44 mc := &Mousectl{ 45 C: ch, 46 Resize: rch, 47 Display: d, 48 } 49 go mouseproc(mc, d, ch, rch) 50 return mc 51 } 52 53 func mouseproc(mc *Mousectl, d *Display, ch chan Mouse, rch chan bool) { 54 for { 55 m, resized, err := d.conn.ReadMouse() 56 if err != nil { 57 log.Fatal("readmouse: ", err) 58 } 59 if resized { 60 rch <- true 61 } 62 mm := Mouse{Point{m.X, m.Y}, m.Buttons, uint32(m.Msec)} 63 ch <- mm 64 // No "mc.Mouse = mm" here! See Mousectl doc comment. 65 } 66 } 67 68 // Read returns the next mouse event. 69 func (mc *Mousectl) Read() Mouse { 70 mc.Display.Flush() 71 m := <-mc.C 72 mc.Mouse = m 73 return m 74 } 75 76 // MoveCursor moves the mouse cursor to the specified location. 77 func (d *Display) MoveCursor(pt Point) error { 78 d.mu.Lock() 79 defer d.mu.Unlock() 80 err := d.conn.MoveTo(pt) 81 if err != nil { 82 fmt.Fprintf(os.Stderr, "MoveTo: %v\n", err) 83 return err 84 } 85 return nil 86 } 87 88 // SwitchCursor sets the mouse cursor to the specified cursor image. 89 // SwitchCursor(nil) changes the cursor to the standard system cursor. 90 func (d *Display) SwitchCursor(c *Cursor) error { 91 d.mu.Lock() 92 defer d.mu.Unlock() 93 err := d.conn.Cursor((*drawfcall.Cursor)(c)) 94 if err != nil { 95 fmt.Fprintf(os.Stderr, "SetCursor: %v\n", err) 96 return err 97 } 98 return nil 99 } 100 101 // SwitchCursor2 sets the mouse cursor to the specified cursor images. 102 // SwitchCursor2(nil, nil) changes the cursor to the standard system cursor. 103 // If c2 is omitted, a scaled version of c is used instead. 104 func (d *Display) SwitchCursor2(c *Cursor, c2 *Cursor2) error { 105 d.mu.Lock() 106 defer d.mu.Unlock() 107 err := d.conn.Cursor2((*drawfcall.Cursor)(c), (*drawfcall.Cursor2)(c2)) 108 if err != nil { 109 fmt.Fprintf(os.Stderr, "SetCursor: %v\n", err) 110 return err 111 } 112 return nil 113 }