9fans.net/go@v0.0.7/cmd/devdraw/screen.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"image"
     6  	godraw "image/draw"
     7  	"log"
     8  	"os"
     9  	"sync"
    10  	"time"
    11  
    12  	"9fans.net/go/draw"
    13  	"9fans.net/go/draw/memdraw"
    14  	"golang.org/x/exp/shiny/driver"
    15  	"golang.org/x/exp/shiny/screen"
    16  	"golang.org/x/mobile/event/key"
    17  	"golang.org/x/mobile/event/lifecycle"
    18  	"golang.org/x/mobile/event/mouse"
    19  	"golang.org/x/mobile/event/paint"
    20  	"golang.org/x/mobile/event/size"
    21  )
    22  
    23  var ScreenPix = draw.XBGR32
    24  
    25  func gfx_main() {
    26  	driver.Main(shinyMain)
    27  }
    28  
    29  var attachChan = make(chan func(screen.Screen) (screen.Window, *Client))
    30  var theWindow screen.Window
    31  
    32  func rpc_attach(client *Client, label, winsize string) (*memdraw.Image, error) {
    33  	done := make(chan bool)
    34  	attachChan <- func(s screen.Screen) (screen.Window, *Client) {
    35  		w, err := s.NewWindow(&screen.NewWindowOptions{
    36  			Title: label,
    37  			// TODO winsize
    38  		})
    39  		if err != nil {
    40  			log.Fatal(err)
    41  		}
    42  		theWindow = w
    43  
    44  	Loop:
    45  		for {
    46  			switch e := w.NextEvent().(type) {
    47  			default:
    48  				log.Printf("skipping %T %+v\n", e, e)
    49  
    50  			case size.Event:
    51  				r := draw.Rect(0, 0, e.WidthPx, e.HeightPx)
    52  				log.Printf("size.Event rect %v\n", r)
    53  				i, err := memdraw.AllocImage(r, ScreenPix)
    54  				if err != nil {
    55  					log.Fatal(err)
    56  				}
    57  				client.impl = &theImpl{i: i, rgba: memimageToRGBA(i)}
    58  				client.displaydpi = int(e.PixelsPerPt * 72)
    59  				client.mouserect = i.R
    60  				w.SendFirst(e)
    61  				break Loop
    62  			}
    63  		}
    64  		close(done)
    65  		return w, client
    66  	}
    67  	<-done
    68  
    69  	return client.impl.(*theImpl).i, nil
    70  }
    71  
    72  func memimageToRGBA(i *memdraw.Image) *image.RGBA {
    73  	return &image.RGBA{
    74  		Pix:    i.BytesAt(i.R.Min),
    75  		Stride: int(i.Width) * 4,
    76  		Rect:   i.R,
    77  	}
    78  }
    79  
    80  type theImpl struct {
    81  	i    *memdraw.Image
    82  	b    screen.Buffer
    83  	rgba *image.RGBA
    84  }
    85  
    86  func (*theImpl) rpc_setlabel(client *Client, label string) {
    87  	done := make(chan bool)
    88  	theWindow.SendFirst(func() {
    89  		// TODO
    90  		close(done)
    91  	})
    92  	<-done
    93  }
    94  
    95  func rpc_shutdown() {
    96  }
    97  
    98  func (impl *theImpl) rpc_flush(client *Client, r draw.Rectangle) {
    99  	theWindow.SendFirst(func() {
   100  		// drawlk protects the pixel data in impl.i.
   101  		// In addition to avoiding a technical data race,
   102  		// the lock avoids drawing partial updates, which makes
   103  		// animations like sweeping windows much less flickery.
   104  		drawlk.Lock()
   105  		defer drawlk.Unlock()
   106  		// fmt.Fprintf(os.Stderr, "flush %v\n", r)
   107  		godraw.Draw(impl.b.RGBA(), impl.b.Bounds(), impl.rgba, impl.b.Bounds().Min, godraw.Src)
   108  		theWindow.Upload(image.Point{}, impl.b, impl.b.Bounds())
   109  		theWindow.Publish()
   110  	})
   111  }
   112  
   113  func (*theImpl) rpc_resizeimg(client *Client) {
   114  	// TODO
   115  }
   116  
   117  var rpcgfxlk sync.Mutex
   118  
   119  func rpc_gfxdrawlock() {
   120  	rpcgfxlk.Lock()
   121  }
   122  
   123  func rpc_gfxdrawunlock() {
   124  	rpcgfxlk.Unlock()
   125  }
   126  
   127  func (*theImpl) rpc_topwin(client *Client) {
   128  }
   129  
   130  func (*theImpl) rpc_resizewindow(client *Client, r draw.Rectangle) {
   131  }
   132  
   133  func (*theImpl) rpc_setmouse(client *Client, p draw.Point) {
   134  }
   135  
   136  func (*theImpl) rpc_setcursor(client *Client, c *draw.Cursor, c2 *draw.Cursor2) {
   137  }
   138  
   139  func rpc_getsnarf() []byte {
   140  	return nil
   141  }
   142  
   143  func rpc_putsnarf(data []byte) {
   144  }
   145  
   146  func (*theImpl) rpc_bouncemouse(client *Client, m draw.Mouse) {
   147  }
   148  
   149  func shinyMain(s screen.Screen) {
   150  	gfx_started()
   151  
   152  	w, client := (<-attachChan)(s)
   153  	close(attachChan)
   154  	defer w.Release()
   155  	impl := client.impl.(*theImpl)
   156  
   157  	// TODO call gfx_started
   158  
   159  	defer func() {
   160  		if impl.b != nil {
   161  			impl.b.Release()
   162  			impl.b = nil
   163  		}
   164  	}()
   165  
   166  	var buttons int
   167  
   168  	for {
   169  		// fmt.Fprintf(os.Stderr, "EVWAIT\n")
   170  		e := w.NextEvent()
   171  		// fmt.Fprintf(os.Stderr, "EV %T %+v\n", e, e)
   172  		switch e := e.(type) {
   173  		case func():
   174  			e()
   175  
   176  		case lifecycle.Event:
   177  			gfx_abortcompose(client)
   178  			if e.To == lifecycle.StageDead {
   179  				return
   180  			}
   181  
   182  		case key.Event:
   183  			// TODO buttons
   184  			if e.Direction != key.DirPress {
   185  				break
   186  			}
   187  			ch := e.Rune
   188  			if ch == '\r' {
   189  				ch = '\n'
   190  			}
   191  			if ch == -1 && int(e.Code) < len(codeKeys) {
   192  				ch = codeKeys[e.Code]
   193  			}
   194  			if ch > 0 {
   195  				gfx_keystroke(client, ch)
   196  			}
   197  
   198  		case mouse.Event:
   199  			// TODO keyboard modifiers
   200  			// TODO buttons
   201  			fmt.Fprintf(os.Stderr, "M %T\n", e)
   202  			if e.Button > 0 {
   203  				if e.Direction == mouse.DirPress {
   204  					buttons |= 1 << (e.Button - 1)
   205  				} else {
   206  					buttons &^= 1 << (e.Button - 1)
   207  				}
   208  			}
   209  			if buttons == 1 {
   210  				if e.Modifiers&key.ModAlt != 0 {
   211  					buttons = 2
   212  				} else if e.Modifiers&key.ModMeta != 0 {
   213  					buttons = 4
   214  				}
   215  			}
   216  			gfx_abortcompose(client)
   217  			// fmt.Fprintf(os.Stderr, "mousetrack %d %d %#b\n", int(e.X), int(e.Y), buttons)
   218  			gfx_mousetrack(client, int(e.X), int(e.Y), buttons, uint32(time.Now().UnixNano()/1e6))
   219  
   220  		case paint.Event:
   221  			// fmt.Fprintf(os.Stderr, "PAINT\n")
   222  			w.Upload(image.Point{}, impl.b, impl.b.Bounds())
   223  			w.Publish()
   224  
   225  		case size.Event:
   226  			// TODO call gfx_replacescreenimg
   227  			if impl.b != nil {
   228  				impl.b.Release()
   229  				impl.b = nil
   230  			}
   231  			var err error
   232  			impl.b, err = s.NewBuffer(e.Size())
   233  			if err != nil {
   234  				log.Fatal(err)
   235  			}
   236  
   237  			r := draw.Rect(0, 0, e.WidthPx, e.HeightPx)
   238  			if r != impl.i.R {
   239  				i, err := memdraw.AllocImage(r, ScreenPix)
   240  				if err != nil {
   241  					log.Fatal(err)
   242  				}
   243  				impl.i = i
   244  				impl.rgba = memimageToRGBA(i)
   245  				client.mouserect = i.R
   246  				client.displaydpi = int(e.PixelsPerPt * 72)
   247  				gfx_replacescreenimage(client, i)
   248  			} else {
   249  				godraw.Draw(impl.b.RGBA(), r, impl.rgba, r.Min, godraw.Src)
   250  			}
   251  
   252  		case error:
   253  			log.Print(e)
   254  		}
   255  	}
   256  }
   257  
   258  var codeKeys = [...]rune{
   259  	// CodeCapsLock
   260  	key.CodeF1:  draw.KeyFn | 1,
   261  	key.CodeF2:  draw.KeyFn | 2,
   262  	key.CodeF3:  draw.KeyFn | 3,
   263  	key.CodeF4:  draw.KeyFn | 4,
   264  	key.CodeF5:  draw.KeyFn | 5,
   265  	key.CodeF6:  draw.KeyFn | 6,
   266  	key.CodeF7:  draw.KeyFn | 7,
   267  	key.CodeF8:  draw.KeyFn | 8,
   268  	key.CodeF9:  draw.KeyFn | 9,
   269  	key.CodeF10: draw.KeyFn | 10,
   270  	key.CodeF11: draw.KeyFn | 11,
   271  	key.CodeF12: draw.KeyFn | 12,
   272  	// draw.KeyFn | 13 is where the non-F keys start,
   273  	// so CodeF13 through CodeF24 are not representable
   274  
   275  	// CodePause
   276  	key.CodeInsert: draw.KeyInsert,
   277  	key.CodeHome:   draw.KeyHome,
   278  	key.CodePageUp: draw.KeyPageUp,
   279  	// CodeDeleteForward
   280  	key.CodeEnd:        draw.KeyEnd,
   281  	key.CodePageDown:   draw.KeyPageDown,
   282  	key.CodeRightArrow: draw.KeyRight,
   283  	key.CodeLeftArrow:  draw.KeyLeft,
   284  	key.CodeDownArrow:  draw.KeyDown,
   285  	key.CodeUpArrow:    draw.KeyUp,
   286  	// CodeKeypadNumLock
   287  	// CodeHelp
   288  	// CodeMute
   289  	// CodeVolumeUp
   290  	// CodeVolumeDown
   291  	key.CodeLeftControl: draw.KeyCtl,
   292  	key.CodeLeftShift:   draw.KeyShift,
   293  	key.CodeLeftAlt:     draw.KeyAlt,
   294  	// CodeLeftGUI
   295  	key.CodeRightControl: draw.KeyCtl,
   296  	key.CodeRightShift:   draw.KeyShift,
   297  	key.CodeRightAlt:     draw.KeyAlt,
   298  	// CodeRightGUI
   299  }