x11.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Copyright 2014 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. //go:build linux && !android
  5. package app
  6. /*
  7. Simple on-screen app debugging for X11. Not an officially supported
  8. development target for apps, as screens with mice are very different
  9. than screens with touch panels.
  10. */
  11. /*
  12. #cgo LDFLAGS: -lEGL -lGLESv2 -lX11
  13. void createWindow(void);
  14. void processEvents(void);
  15. void swapBuffers(void);
  16. */
  17. import "C"
  18. import (
  19. "runtime"
  20. "time"
  21. "golang.org/x/mobile/event/lifecycle"
  22. "golang.org/x/mobile/event/paint"
  23. "golang.org/x/mobile/event/size"
  24. "golang.org/x/mobile/event/touch"
  25. "golang.org/x/mobile/geom"
  26. )
  27. func init() {
  28. theApp.registerGLViewportFilter()
  29. }
  30. func main(f func(App)) {
  31. runtime.LockOSThread()
  32. workAvailable := theApp.worker.WorkAvailable()
  33. C.createWindow()
  34. // TODO: send lifecycle events when e.g. the X11 window is iconified or moved off-screen.
  35. theApp.sendLifecycle(lifecycle.StageFocused)
  36. // TODO: translate X11 expose events to shiny paint events, instead of
  37. // sending this synthetic paint event as a hack.
  38. theApp.eventsIn <- paint.Event{}
  39. donec := make(chan struct{})
  40. go func() {
  41. // close the donec channel in a defer statement
  42. // so that we could still be able to return even
  43. // if f panics.
  44. defer close(donec)
  45. f(theApp)
  46. }()
  47. // TODO: can we get the actual vsync signal?
  48. ticker := time.NewTicker(time.Second / 60)
  49. defer ticker.Stop()
  50. var tc <-chan time.Time
  51. for {
  52. select {
  53. case <-donec:
  54. return
  55. case <-workAvailable:
  56. theApp.worker.DoWork()
  57. case <-theApp.publish:
  58. C.swapBuffers()
  59. tc = ticker.C
  60. case <-tc:
  61. tc = nil
  62. theApp.publishResult <- PublishResult{}
  63. }
  64. C.processEvents()
  65. }
  66. }
  67. //export onResize
  68. func onResize(w, h int) {
  69. // TODO(nigeltao): don't assume 72 DPI. DisplayWidth and DisplayWidthMM
  70. // is probably the best place to start looking.
  71. pixelsPerPt := float32(1)
  72. theApp.eventsIn <- size.Event{
  73. WidthPx: w,
  74. HeightPx: h,
  75. WidthPt: geom.Pt(w),
  76. HeightPt: geom.Pt(h),
  77. PixelsPerPt: pixelsPerPt,
  78. }
  79. }
  80. func sendTouch(t touch.Type, x, y float32) {
  81. theApp.eventsIn <- touch.Event{
  82. X: x,
  83. Y: y,
  84. Sequence: 0, // TODO: button??
  85. Type: t,
  86. }
  87. }
  88. //export onTouchBegin
  89. func onTouchBegin(x, y float32) { sendTouch(touch.TypeBegin, x, y) }
  90. //export onTouchMove
  91. func onTouchMove(x, y float32) { sendTouch(touch.TypeMove, x, y) }
  92. //export onTouchEnd
  93. func onTouchEnd(x, y float32) { sendTouch(touch.TypeEnd, x, y) }
  94. var stopped bool
  95. //export onStop
  96. func onStop() {
  97. if stopped {
  98. return
  99. }
  100. stopped = true
  101. theApp.sendLifecycle(lifecycle.StageDead)
  102. theApp.eventsIn <- stopPumping{}
  103. }