Adding upstream version 0.0~git20250520.a1d9079+dfsg.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
590ac7ff5f
commit
20149b7f3a
456 changed files with 70406 additions and 0 deletions
213
app/app.go
Normal file
213
app/app.go
Normal file
|
@ -0,0 +1,213 @@
|
|||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build linux || darwin || windows
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"golang.org/x/mobile/event/lifecycle"
|
||||
"golang.org/x/mobile/event/size"
|
||||
"golang.org/x/mobile/gl"
|
||||
_ "golang.org/x/mobile/internal/mobileinit"
|
||||
)
|
||||
|
||||
// Main is called by the main.main function to run the mobile application.
|
||||
//
|
||||
// It calls f on the App, in a separate goroutine, as some OS-specific
|
||||
// libraries require being on 'the main thread'.
|
||||
func Main(f func(App)) {
|
||||
main(f)
|
||||
}
|
||||
|
||||
// App is how a GUI mobile application interacts with the OS.
|
||||
type App interface {
|
||||
// Events returns the events channel. It carries events from the system to
|
||||
// the app. The type of such events include:
|
||||
// - lifecycle.Event
|
||||
// - mouse.Event
|
||||
// - paint.Event
|
||||
// - size.Event
|
||||
// - touch.Event
|
||||
// from the golang.org/x/mobile/event/etc packages. Other packages may
|
||||
// define other event types that are carried on this channel.
|
||||
Events() <-chan interface{}
|
||||
|
||||
// Send sends an event on the events channel. It does not block.
|
||||
Send(event interface{})
|
||||
|
||||
// Publish flushes any pending drawing commands, such as OpenGL calls, and
|
||||
// swaps the back buffer to the screen.
|
||||
Publish() PublishResult
|
||||
|
||||
// TODO: replace filters (and the Events channel) with a NextEvent method?
|
||||
|
||||
// Filter calls each registered event filter function in sequence.
|
||||
Filter(event interface{}) interface{}
|
||||
|
||||
// RegisterFilter registers a event filter function to be called by Filter. The
|
||||
// function can return a different event, or return nil to consume the event,
|
||||
// but the function can also return its argument unchanged, where its purpose
|
||||
// is to trigger a side effect rather than modify the event.
|
||||
RegisterFilter(f func(interface{}) interface{})
|
||||
}
|
||||
|
||||
// PublishResult is the result of an App.Publish call.
|
||||
type PublishResult struct {
|
||||
// BackBufferPreserved is whether the contents of the back buffer was
|
||||
// preserved. If false, the contents are undefined.
|
||||
BackBufferPreserved bool
|
||||
}
|
||||
|
||||
var theApp = &app{
|
||||
eventsOut: make(chan interface{}),
|
||||
lifecycleStage: lifecycle.StageDead,
|
||||
publish: make(chan struct{}),
|
||||
publishResult: make(chan PublishResult),
|
||||
}
|
||||
|
||||
func init() {
|
||||
theApp.eventsIn = pump(theApp.eventsOut)
|
||||
theApp.glctx, theApp.worker = gl.NewContext()
|
||||
}
|
||||
|
||||
func (a *app) sendLifecycle(to lifecycle.Stage) {
|
||||
if a.lifecycleStage == to {
|
||||
return
|
||||
}
|
||||
a.eventsIn <- lifecycle.Event{
|
||||
From: a.lifecycleStage,
|
||||
To: to,
|
||||
DrawContext: a.glctx,
|
||||
}
|
||||
a.lifecycleStage = to
|
||||
}
|
||||
|
||||
type app struct {
|
||||
filters []func(interface{}) interface{}
|
||||
|
||||
eventsOut chan interface{}
|
||||
eventsIn chan interface{}
|
||||
lifecycleStage lifecycle.Stage
|
||||
publish chan struct{}
|
||||
publishResult chan PublishResult
|
||||
|
||||
glctx gl.Context
|
||||
worker gl.Worker
|
||||
}
|
||||
|
||||
func (a *app) Events() <-chan interface{} {
|
||||
return a.eventsOut
|
||||
}
|
||||
|
||||
func (a *app) Send(event interface{}) {
|
||||
a.eventsIn <- event
|
||||
}
|
||||
|
||||
func (a *app) Publish() PublishResult {
|
||||
// gl.Flush is a lightweight (on modern GL drivers) blocking call
|
||||
// that ensures all GL functions pending in the gl package have
|
||||
// been passed onto the GL driver before the app package attempts
|
||||
// to swap the screen buffer.
|
||||
//
|
||||
// This enforces that the final receive (for this paint cycle) on
|
||||
// gl.WorkAvailable happens before the send on endPaint.
|
||||
a.glctx.Flush()
|
||||
a.publish <- struct{}{}
|
||||
return <-a.publishResult
|
||||
}
|
||||
|
||||
func (a *app) Filter(event interface{}) interface{} {
|
||||
for _, f := range a.filters {
|
||||
event = f(event)
|
||||
}
|
||||
return event
|
||||
}
|
||||
|
||||
func (a *app) RegisterFilter(f func(interface{}) interface{}) {
|
||||
a.filters = append(a.filters, f)
|
||||
}
|
||||
|
||||
type stopPumping struct{}
|
||||
|
||||
// pump returns a channel src such that sending on src will eventually send on
|
||||
// dst, in order, but that src will always be ready to send/receive soon, even
|
||||
// if dst currently isn't. It is effectively an infinitely buffered channel.
|
||||
//
|
||||
// In particular, goroutine A sending on src will not deadlock even if goroutine
|
||||
// B that's responsible for receiving on dst is currently blocked trying to
|
||||
// send to A on a separate channel.
|
||||
//
|
||||
// Send a stopPumping on the src channel to close the dst channel after all queued
|
||||
// events are sent on dst. After that, other goroutines can still send to src,
|
||||
// so that such sends won't block forever, but such events will be ignored.
|
||||
func pump(dst chan interface{}) (src chan interface{}) {
|
||||
src = make(chan interface{})
|
||||
go func() {
|
||||
// initialSize is the initial size of the circular buffer. It must be a
|
||||
// power of 2.
|
||||
const initialSize = 16
|
||||
i, j, buf, mask := 0, 0, make([]interface{}, initialSize), initialSize-1
|
||||
|
||||
srcActive := true
|
||||
for {
|
||||
maybeDst := dst
|
||||
if i == j {
|
||||
maybeDst = nil
|
||||
}
|
||||
if maybeDst == nil && !srcActive {
|
||||
// Pump is stopped and empty.
|
||||
break
|
||||
}
|
||||
|
||||
select {
|
||||
case maybeDst <- buf[i&mask]:
|
||||
buf[i&mask] = nil
|
||||
i++
|
||||
|
||||
case e := <-src:
|
||||
if _, ok := e.(stopPumping); ok {
|
||||
srcActive = false
|
||||
continue
|
||||
}
|
||||
|
||||
if !srcActive {
|
||||
continue
|
||||
}
|
||||
|
||||
// Allocate a bigger buffer if necessary.
|
||||
if i+len(buf) == j {
|
||||
b := make([]interface{}, 2*len(buf))
|
||||
n := copy(b, buf[j&mask:])
|
||||
copy(b[n:], buf[:j&mask])
|
||||
i, j = 0, len(buf)
|
||||
buf, mask = b, len(b)-1
|
||||
}
|
||||
|
||||
buf[j&mask] = e
|
||||
j++
|
||||
}
|
||||
}
|
||||
|
||||
close(dst)
|
||||
// Block forever.
|
||||
for range src {
|
||||
}
|
||||
}()
|
||||
return src
|
||||
}
|
||||
|
||||
// TODO: do this for all build targets, not just linux (x11 and Android)? If
|
||||
// so, should package gl instead of this package call RegisterFilter??
|
||||
//
|
||||
// TODO: does Android need this?? It seems to work without it (Nexus 7,
|
||||
// KitKat). If only x11 needs this, should we move this to x11.go??
|
||||
func (a *app) registerGLViewportFilter() {
|
||||
a.RegisterFilter(func(e interface{}) interface{} {
|
||||
if e, ok := e.(size.Event); ok {
|
||||
a.glctx.Viewport(0, 0, e.WidthPx, e.HeightPx)
|
||||
}
|
||||
return e
|
||||
})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue