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  }