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  }