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  }