9fans.net/go@v0.0.5/draw/drawfcall/mux_plan9.go (about)

     1  package drawfcall
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"encoding/binary"
     7  	"errors"
     8  	"fmt"
     9  	"image"
    10  	"io/ioutil"
    11  	"os"
    12  	"strconv"
    13  	"strings"
    14  	"sync"
    15  )
    16  
    17  type Conn struct {
    18  	ctl      *os.File
    19  	data     *os.File
    20  	cons     *bufio.Reader
    21  	consctl  *os.File
    22  	mouse    *os.File
    23  	snarf    *os.File
    24  	cursor   *os.File
    25  	n        int // connection number
    26  	initCtl  []byte
    27  	oldLabel string
    28  
    29  	readData   []byte
    30  	ctlWasRead bool
    31  	lk         sync.Mutex
    32  }
    33  
    34  func New() (*Conn, error) {
    35  	ctl, err := os.OpenFile("/dev/draw/new", os.O_RDWR, 0)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  
    40  	var b [12*12 + 1]byte
    41  	nr, err := ctl.Read(b[:])
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  	f := strings.Fields(string(b[:nr]))
    46  	if len(f) != 12 {
    47  		return nil, fmt.Errorf("bad ctl file")
    48  	}
    49  	n, err := strconv.Atoi(f[0])
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	data, err := os.OpenFile(fmt.Sprintf("/dev/draw/%v/data", n), os.O_RDWR, 0)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	cons, err := os.Open("/dev/cons")
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	consctl, err := os.OpenFile("/dev/consctl", os.O_WRONLY, 0)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	_, err = consctl.WriteString("rawon")
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	mouse, err := os.OpenFile("/dev/mouse", os.O_RDWR, 0)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  	snarf, err := os.Open("/dev/snarf")
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	cursor, err := os.OpenFile("/dev/cursor", os.O_WRONLY, 0)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	return &Conn{
    86  		ctl:     ctl,
    87  		data:    data,
    88  		cons:    bufio.NewReader(cons),
    89  		consctl: consctl,
    90  		mouse:   mouse,
    91  		snarf:   snarf,
    92  		cursor:  cursor,
    93  		initCtl: b[:nr],
    94  		n:       n,
    95  	}, nil
    96  }
    97  
    98  func (c *Conn) Close() error {
    99  	return c.ctl.Close()
   100  }
   101  
   102  func (c *Conn) Init(label, winsize string) error {
   103  	if b, err := ioutil.ReadFile("/dev/label"); err == nil {
   104  		c.oldLabel = string(b)
   105  	}
   106  	// Ignore error because we may not be running in rio
   107  	ioutil.WriteFile("/dev/label", []byte(label), 0600)
   108  	return nil
   109  }
   110  
   111  func atoi(s string) (n int) {
   112  	n, _ = strconv.Atoi(s)
   113  	return
   114  }
   115  
   116  func (c *Conn) ReadMouse() (m Mouse, resized bool, err error) {
   117  	var buf [1 + 5*12]byte
   118  	var nr int
   119  
   120  	nr, err = c.mouse.Read(buf[:])
   121  	if err != nil {
   122  		return
   123  	}
   124  	f := strings.Fields(string(buf[:nr]))
   125  	if len(f) != 5 {
   126  		err = errors.New("bad mouse event")
   127  		return
   128  	}
   129  	m.Point = image.Pt(atoi(f[1]), atoi(f[2]))
   130  	m.Buttons = atoi(f[3])
   131  	m.Msec = atoi(f[4])
   132  	if f[0] == "r" {
   133  		resized = true
   134  	}
   135  	return
   136  }
   137  
   138  func (c *Conn) ReadKbd() (r rune, err error) {
   139  	r, _, err = c.cons.ReadRune()
   140  	return
   141  }
   142  
   143  func (c *Conn) MoveTo(p image.Point) error {
   144  	_, err := fmt.Fprintf(c.mouse, "m%11d %11d ", p.X, p.Y)
   145  	return err
   146  }
   147  
   148  func (c *Conn) Cursor(cursor *Cursor) error {
   149  	if cursor == nil {
   150  		// Revert to default cursor (Arrow)
   151  		_, err := c.cursor.Write([]byte{0})
   152  		return err
   153  	}
   154  	b := make([]byte, 2*4+len(cursor.Clr)+len(cursor.Set))
   155  	i := 0
   156  	binary.LittleEndian.PutUint32(b[i:], uint32(cursor.Point.X))
   157  	i += 4
   158  	binary.LittleEndian.PutUint32(b[i:], uint32(cursor.Point.Y))
   159  	i += 4
   160  	i += copy(b[i:], cursor.Clr[:])
   161  	i += copy(b[i:], cursor.Set[:])
   162  	_, err := c.cursor.Write(b)
   163  	return err
   164  }
   165  
   166  func (c *Conn) BounceMouse(m *Mouse) error {
   167  	panic("unimplemented")
   168  }
   169  
   170  func (c *Conn) Label(label string) error {
   171  	panic("unimplemented")
   172  }
   173  
   174  // Return values are bytes copied, actual size, error.
   175  func (c *Conn) ReadSnarf(b []byte) (int, int, error) {
   176  	_, err := c.snarf.Seek(0, 0)
   177  	if err != nil {
   178  		return 0, 0, err
   179  	}
   180  	n, err := c.snarf.Read(b)
   181  	return n, n, err
   182  }
   183  
   184  func (c *Conn) WriteSnarf(snarf []byte) error {
   185  	// /dev/snarf updates when the file is closed, so we must open it for each call
   186  	f, err := os.OpenFile("/dev/snarf", os.O_WRONLY, 0)
   187  	if err != nil {
   188  		return err
   189  	}
   190  	_, err = f.Write(snarf)
   191  	if err != nil {
   192  		return err
   193  	}
   194  	return f.Close()
   195  }
   196  
   197  func (c *Conn) Top() error {
   198  	panic("unimplemented")
   199  }
   200  
   201  func (c *Conn) Resize(r image.Rectangle) error {
   202  	panic("unimplemented")
   203  }
   204  
   205  func (c *Conn) ReadDraw(b []byte) (n int, err error) {
   206  	c.lk.Lock()
   207  	if len(c.readData) > 0 {
   208  		n = copy(b, c.readData)
   209  		c.readData = c.readData[n:]
   210  		c.lk.Unlock()
   211  		return n, nil
   212  	}
   213  	c.lk.Unlock()
   214  	return c.data.Read(b[:])
   215  }
   216  
   217  func bplong(b []byte, n uint32) {
   218  	binary.LittleEndian.PutUint32(b, n)
   219  }
   220  
   221  func (c *Conn) WriteDraw(b []byte) (int, error) {
   222  	i := 0
   223  Loop:
   224  	for i < len(b) {
   225  		switch b[i] {
   226  		case 'J': // set image 0 to screen image
   227  			i++
   228  
   229  		case 'I': // get image info: 'I'
   230  			c.lk.Lock()
   231  			if !c.ctlWasRead {
   232  				c.readData = append(c.readData, c.initCtl...)
   233  				c.ctlWasRead = true
   234  			} else {
   235  				b := make([]byte, 12*12)
   236  				n, err := c.ctl.Read(b)
   237  				if err != nil {
   238  					c.lk.Unlock()
   239  					return 0, err
   240  				}
   241  				c.readData = append(c.readData, b[:n]...)
   242  			}
   243  			c.lk.Unlock()
   244  			i++
   245  
   246  		case 'q': // query: 'Q' n[1] queryspec[n]
   247  			if bytes.Equal(b, []byte{'q', 1, 'd'}) {
   248  				dpi := fmt.Sprintf("%12d", 100)
   249  				c.lk.Lock()
   250  				c.readData = append(c.readData, []byte(dpi)...)
   251  				c.lk.Unlock()
   252  			}
   253  			i += 1 + 1 + int(b[1])
   254  
   255  		default:
   256  			break Loop
   257  		}
   258  	}
   259  	if len(b[i:]) == 0 {
   260  		return i, nil
   261  	}
   262  	n, err := c.data.Write(b[i:])
   263  	return n + i, err
   264  }