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 }