github.com/provpn/mobile@v0.0.0-20210315122651-28c475f89f6c/app/x11.go (about)

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