app: introduce Config and start registration
Config provides a way to concurrently access Width and Height. Register provides a way for packages to run code on app state change without plumbing changes all the way to the process main function. This is motivated by gl/glutil.Image which needs to rebuild its textures on start/stop and can be deeply nested. (See golang.org/cl/9707 for the followup.) Tested manually on android and darwin/amd64. Doing this kind makes it clear any CL modifying this code needs a lot of manual testing right now, so some kind of trybot support is something I'm going to prioritise. Fixes golang/go#10686 Fixes golang/go#10461 Fixes golang/go#10442 Fixes golang/go#10226 Updates golang/go#10327 Change-Id: I2882ebf3995b6ed857cda823e94fbb17c54b43a8 Reviewed-on: https://go-review.googlesource.com/9708 Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
parent
601608a0e0
commit
5cddc1460e
|
@ -148,12 +148,13 @@ static void* call_main_and_wait() {
|
|||
|
||||
// Runtime entry point when using NativeActivity.
|
||||
void ANativeActivity_onCreate(ANativeActivity *activity, void* savedState, size_t savedStateSize) {
|
||||
// Note that activity->clazz is mis-named.
|
||||
current_vm = activity->vm;
|
||||
current_ctx = (*activity->env)->NewGlobalRef(activity->env, activity->clazz);
|
||||
current_native_activity = activity;
|
||||
|
||||
call_main_and_wait();
|
||||
if (current_ctx == NULL) {
|
||||
// Note that activity->clazz is mis-named.
|
||||
current_vm = activity->vm;
|
||||
current_ctx = (*activity->env)->NewGlobalRef(activity->env, activity->clazz);
|
||||
call_main_and_wait();
|
||||
}
|
||||
|
||||
// These functions match the methods on Activity, described at
|
||||
// http://developer.android.com/reference/android/app/Activity.html
|
||||
|
|
|
@ -69,8 +69,6 @@ import (
|
|||
"golang.org/x/mobile/geom"
|
||||
)
|
||||
|
||||
var running = make(chan struct{}) // closed after app.Run is called
|
||||
|
||||
//export callMain
|
||||
func callMain(mainPC uintptr) {
|
||||
for _, name := range []string{"TMPDIR", "PATH", "LD_LIBRARY_PATH"} {
|
||||
|
@ -79,7 +77,7 @@ func callMain(mainPC uintptr) {
|
|||
C.free(unsafe.Pointer(n))
|
||||
}
|
||||
go callfn.CallFn(mainPC)
|
||||
<-running
|
||||
<-mainCalled
|
||||
log.Print("app.Run called")
|
||||
}
|
||||
|
||||
|
@ -187,20 +185,17 @@ func onConfigurationChanged(activity *C.ANativeActivity) {
|
|||
func onLowMemory(activity *C.ANativeActivity) {
|
||||
}
|
||||
|
||||
type androidState struct {
|
||||
}
|
||||
|
||||
func (androidState) JavaVM() unsafe.Pointer {
|
||||
func (Config) JavaVM() unsafe.Pointer {
|
||||
return unsafe.Pointer(C.current_vm)
|
||||
}
|
||||
|
||||
// ClassFinder returns a C function pointer for finding a given class using
|
||||
// the app class loader. (jclass) (*fn)(JNIEnv*, const char*).
|
||||
func (androidState) ClassFinder() unsafe.Pointer {
|
||||
func (Config) ClassFinder() unsafe.Pointer {
|
||||
return unsafe.Pointer(C.app_find_class)
|
||||
}
|
||||
|
||||
func (androidState) AndroidContext() unsafe.Pointer {
|
||||
func (Config) AndroidContext() unsafe.Pointer {
|
||||
return unsafe.Pointer(C.current_ctx)
|
||||
}
|
||||
|
||||
|
@ -261,17 +256,9 @@ func (a *asset) Close() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func runStart(cb Callbacks) {
|
||||
State = androidState{}
|
||||
|
||||
if cb.Start != nil {
|
||||
cb.Start()
|
||||
}
|
||||
}
|
||||
|
||||
// notifyInitDone informs Java that the program is initialized.
|
||||
// A NativeActivity will not create a window until this is called.
|
||||
func run(cb Callbacks) {
|
||||
func run(callbacks []Callbacks) {
|
||||
// We want to keep the event loop on a consistent OS thread.
|
||||
runtime.LockOSThread()
|
||||
|
||||
|
@ -281,12 +268,14 @@ func run(cb Callbacks) {
|
|||
C.free(unsafe.Pointer(ctag))
|
||||
C.free(unsafe.Pointer(cstr))
|
||||
|
||||
close(mainCalled)
|
||||
if C.current_native_activity == nil {
|
||||
runStart(cb)
|
||||
close(running)
|
||||
stateStart(callbacks)
|
||||
// TODO: stateStop under some conditions.
|
||||
select {}
|
||||
} else {
|
||||
close(running)
|
||||
windowDrawLoop(cb, <-windowCreated, queue)
|
||||
for w := range windowCreated {
|
||||
windowDraw(callbacks, w, queue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
52
app/app.go
52
app/app.go
|
@ -10,14 +10,20 @@ import (
|
|||
"io"
|
||||
|
||||
"golang.org/x/mobile/event"
|
||||
"golang.org/x/mobile/geom"
|
||||
)
|
||||
|
||||
var callbacks []Callbacks
|
||||
|
||||
// Run starts the app.
|
||||
//
|
||||
// It must be called directly from the main function and will
|
||||
// block until the app exits.
|
||||
//
|
||||
// TODO(crawshaw): Remove cb parameter.
|
||||
func Run(cb Callbacks) {
|
||||
run(cb)
|
||||
callbacks = append(callbacks, cb)
|
||||
run(callbacks)
|
||||
}
|
||||
|
||||
// Callbacks is the set of functions called by the app.
|
||||
|
@ -38,7 +44,7 @@ type Callbacks struct {
|
|||
|
||||
// Stop is called shortly before a program is suspended.
|
||||
//
|
||||
// When Stop is received, the app is no longer visible and not is
|
||||
// When Stop is received, the app is no longer visible and is not
|
||||
// receiving events. It should:
|
||||
//
|
||||
// - Save any state the user expects saved (for example text).
|
||||
|
@ -63,6 +69,15 @@ type Callbacks struct {
|
|||
|
||||
// Touch is called by the app when a touch event occurs.
|
||||
Touch func(event.Touch)
|
||||
|
||||
// Config is called by the app when configuration has changed.
|
||||
Config func(new, old Config)
|
||||
}
|
||||
|
||||
// Register registers a set of callbacks.
|
||||
// Must be called before Run.
|
||||
func Register(cb Callbacks) {
|
||||
callbacks = append(callbacks, cb)
|
||||
}
|
||||
|
||||
// Open opens a named asset.
|
||||
|
@ -87,9 +102,22 @@ type ReadSeekCloser interface {
|
|||
io.Closer
|
||||
}
|
||||
|
||||
// State is global application-specific state.
|
||||
// GetConfig returns the current application state.
|
||||
// It will block until Run has been called.
|
||||
func GetConfig() Config {
|
||||
select {
|
||||
case <-mainCalled:
|
||||
default:
|
||||
panic("app.GetConfig is not available before app.Run is called")
|
||||
}
|
||||
configCurMu.Lock()
|
||||
defer configCurMu.Unlock()
|
||||
return configCur
|
||||
}
|
||||
|
||||
// Config is global application-specific configuration.
|
||||
//
|
||||
// The State variable also holds operating system specific state.
|
||||
// The Config variable also holds operating system specific state.
|
||||
// Android apps have the extra methods:
|
||||
//
|
||||
// // JavaVM returns a JNI *JavaVM.
|
||||
|
@ -98,5 +126,17 @@ type ReadSeekCloser interface {
|
|||
// // AndroidContext returns a jobject for the app android.context.Context.
|
||||
// AndroidContext() unsafe.Pointer
|
||||
//
|
||||
// State is not valid until Run has been called.
|
||||
var State interface{}
|
||||
// These extra methods are deliberately difficult to access because they
|
||||
// must be used with care. Their use implies the use of cgo, which probably
|
||||
// requires you understand the initialization process in the app package.
|
||||
// Also care must be taken to write both Android, iOS, and desktop-testing
|
||||
// versions to maintain portability.
|
||||
type Config struct {
|
||||
// Width is the width of the device screen.
|
||||
Width geom.Pt
|
||||
|
||||
// Height is the height of the device screen.
|
||||
Height geom.Pt
|
||||
|
||||
// TODO: Orientation
|
||||
}
|
||||
|
|
|
@ -52,20 +52,23 @@ func init() {
|
|||
initThreadID = uint64(C.threadID())
|
||||
}
|
||||
|
||||
func run(callbacks Callbacks) {
|
||||
func run(callbacks []Callbacks) {
|
||||
if tid := uint64(C.threadID()); tid != initThreadID {
|
||||
log.Fatalf("app.Run called on thread %d, but app.init ran on %d", tid, initThreadID)
|
||||
}
|
||||
cb = callbacks
|
||||
close(mainCalled)
|
||||
C.runApp()
|
||||
}
|
||||
|
||||
//export setGeom
|
||||
func setGeom(pixelsPerPt float32, width, height int) {
|
||||
// Macs default to 72 DPI, so scales are equivalent.
|
||||
geom.PixelsPerPt = pixelsPerPt
|
||||
geom.Width = geom.Pt(float32(width) / pixelsPerPt)
|
||||
geom.Height = geom.Pt(float32(height) / pixelsPerPt)
|
||||
if geom.PixelsPerPt == 0 {
|
||||
// Macs default to 72 DPI, so scales are equivalent.
|
||||
geom.PixelsPerPt = pixelsPerPt
|
||||
}
|
||||
configAlt.Width = geom.Pt(float32(width) / geom.PixelsPerPt)
|
||||
configAlt.Height = geom.Pt(float32(height) / geom.PixelsPerPt)
|
||||
configSwap(callbacks)
|
||||
}
|
||||
|
||||
func initGL() {
|
||||
|
@ -74,12 +77,9 @@ func initGL() {
|
|||
var id C.GLuint
|
||||
C.glGenVertexArrays(1, &id)
|
||||
C.glBindVertexArray(id)
|
||||
if cb.Start != nil {
|
||||
cb.Start()
|
||||
}
|
||||
stateStart(callbacks)
|
||||
}
|
||||
|
||||
var cb Callbacks
|
||||
var initGLOnce sync.Once
|
||||
|
||||
var touchEvents struct {
|
||||
|
@ -94,7 +94,7 @@ func sendTouch(ty event.TouchType, x, y float32) {
|
|||
Type: ty,
|
||||
Loc: geom.Point{
|
||||
X: geom.Pt(x / geom.PixelsPerPt),
|
||||
Y: geom.Height - geom.Pt(y/geom.PixelsPerPt),
|
||||
Y: GetConfig().Height - geom.Pt(y/geom.PixelsPerPt),
|
||||
},
|
||||
})
|
||||
touchEvents.Unlock()
|
||||
|
@ -124,17 +124,21 @@ func drawgl(ctx C.GLintptr) {
|
|||
pending := touchEvents.pending
|
||||
touchEvents.pending = nil
|
||||
touchEvents.Unlock()
|
||||
if cb.Touch != nil {
|
||||
for _, e := range pending {
|
||||
cb.Touch(e)
|
||||
for _, cb := range callbacks {
|
||||
if cb.Touch != nil {
|
||||
for _, e := range pending {
|
||||
cb.Touch(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: is the library or the app responsible for clearing the buffers?
|
||||
gl.ClearColor(0, 0, 0, 1)
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
||||
if cb.Draw != nil {
|
||||
cb.Draw()
|
||||
for _, cb := range callbacks {
|
||||
if cb.Draw != nil {
|
||||
cb.Draw()
|
||||
}
|
||||
}
|
||||
|
||||
C.unlockContext(ctx)
|
||||
|
|
|
@ -110,11 +110,14 @@ func setGeom(width, height int) {
|
|||
if geom.PixelsPerPt == 0 {
|
||||
geom.PixelsPerPt = float32(ppi()) / 72
|
||||
}
|
||||
geom.Width = geom.Pt(float32(width) / geom.PixelsPerPt)
|
||||
geom.Height = geom.Pt(float32(height) / geom.PixelsPerPt)
|
||||
configAlt.Width = geom.Pt(float32(width) / geom.PixelsPerPt)
|
||||
configAlt.Height = geom.Pt(float32(height) / geom.PixelsPerPt)
|
||||
configSwap()
|
||||
|
||||
}
|
||||
|
||||
func initGL() {
|
||||
stateStart()
|
||||
}
|
||||
|
||||
var cb Callbacks
|
||||
|
|
|
@ -90,7 +90,7 @@ import (
|
|||
"golang.org/x/mobile/gl"
|
||||
)
|
||||
|
||||
func windowDrawLoop(cb Callbacks, w *C.ANativeWindow, queue *C.AInputQueue) {
|
||||
func windowDraw(callbacks []Callbacks, w *C.ANativeWindow, queue *C.AInputQueue) {
|
||||
C.createEGLWindow(w)
|
||||
|
||||
// TODO: is the library or the app responsible for clearing the buffers?
|
||||
|
@ -102,51 +102,61 @@ func windowDrawLoop(cb Callbacks, w *C.ANativeWindow, queue *C.AInputQueue) {
|
|||
log.Printf("GL initialization error: %s", errv)
|
||||
}
|
||||
|
||||
geom.Width = geom.Pt(float32(C.windowWidth) / geom.PixelsPerPt)
|
||||
geom.Height = geom.Pt(float32(C.windowHeight) / geom.PixelsPerPt)
|
||||
configAlt.Width = geom.Pt(float32(C.windowWidth) / geom.PixelsPerPt)
|
||||
configAlt.Height = geom.Pt(float32(C.windowHeight) / geom.PixelsPerPt)
|
||||
configSwap(callbacks)
|
||||
|
||||
// Wait until geometry and GL is initialized before cb.Start.
|
||||
runStart(cb)
|
||||
stateStart(callbacks)
|
||||
|
||||
for {
|
||||
processEvents(cb, queue)
|
||||
processEvents(callbacks, queue)
|
||||
select {
|
||||
case <-windowRedrawNeeded:
|
||||
// Re-query the width and height.
|
||||
C.querySurfaceWidthAndHeight()
|
||||
geom.Width = geom.Pt(float32(C.windowWidth) / geom.PixelsPerPt)
|
||||
geom.Height = geom.Pt(float32(C.windowHeight) / geom.PixelsPerPt)
|
||||
configAlt.Width = geom.Pt(float32(C.windowWidth) / geom.PixelsPerPt)
|
||||
configAlt.Height = geom.Pt(float32(C.windowHeight) / geom.PixelsPerPt)
|
||||
gl.Viewport(0, 0, int(C.windowWidth), int(C.windowHeight))
|
||||
configSwap(callbacks)
|
||||
case <-windowDestroyed:
|
||||
if cb.Stop != nil {
|
||||
cb.Stop()
|
||||
}
|
||||
stateStop(callbacks)
|
||||
return
|
||||
default:
|
||||
if cb.Draw != nil {
|
||||
cb.Draw()
|
||||
for _, cb := range callbacks {
|
||||
if cb.Draw != nil {
|
||||
cb.Draw()
|
||||
}
|
||||
}
|
||||
C.eglSwapBuffers(C.display, C.surface)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func processEvents(cb Callbacks, queue *C.AInputQueue) {
|
||||
func processEvents(callbacks []Callbacks, queue *C.AInputQueue) {
|
||||
var event *C.AInputEvent
|
||||
for C.AInputQueue_getEvent(queue, &event) >= 0 {
|
||||
if C.AInputQueue_preDispatchEvent(queue, event) != 0 {
|
||||
continue
|
||||
}
|
||||
processEvent(cb, event)
|
||||
processEvent(callbacks, event)
|
||||
C.AInputQueue_finishEvent(queue, event, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func processEvent(cb Callbacks, e *C.AInputEvent) {
|
||||
func processEvent(callbacks []Callbacks, e *C.AInputEvent) {
|
||||
switch C.AInputEvent_getType(e) {
|
||||
case C.AINPUT_EVENT_TYPE_KEY:
|
||||
log.Printf("TODO input event: key")
|
||||
case C.AINPUT_EVENT_TYPE_MOTION:
|
||||
if cb.Touch == nil {
|
||||
// TODO: calculate hasTouch once in run
|
||||
hasTouch := false
|
||||
for _, cb := range callbacks {
|
||||
if cb.Touch != nil {
|
||||
hasTouch = true
|
||||
}
|
||||
}
|
||||
if !hasTouch {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -165,14 +175,19 @@ func processEvent(cb Callbacks, e *C.AInputEvent) {
|
|||
if i == upDownIndex {
|
||||
typ = upDownTyp
|
||||
}
|
||||
cb.Touch(event.Touch{
|
||||
t := event.Touch{
|
||||
ID: event.TouchSequenceID(C.AMotionEvent_getPointerId(e, i)),
|
||||
Type: typ,
|
||||
Loc: geom.Point{
|
||||
X: geom.Pt(float32(C.AMotionEvent_getX(e, i)) / geom.PixelsPerPt),
|
||||
Y: geom.Pt(float32(C.AMotionEvent_getY(e, i)) / geom.PixelsPerPt),
|
||||
},
|
||||
})
|
||||
}
|
||||
for _, cb := range callbacks {
|
||||
if cb.Touch != nil {
|
||||
cb.Touch(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
log.Printf("unknown input event, type=%d", C.AInputEvent_getType(e))
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
package app
|
||||
|
||||
/*
|
||||
There are three notions of state at work in this package.
|
||||
|
||||
The first is Unix process state. Because mobile devices can be compiled
|
||||
as -buildmode=c-shared and -buildmode=c-archive, there is code in this
|
||||
package executed by global constructor which runs before (and even is
|
||||
reponsible for triggering) the Go main function call. This is tracked
|
||||
by the mainCalled channel.
|
||||
|
||||
The second is runState. An app may "Start" and "Stop" multiple times
|
||||
over the life of the unix process. This involes the creation and
|
||||
destruction of OpenGL windows and calling user Callbacks. Some user
|
||||
functions must block in the stop state.
|
||||
|
||||
The third is Config, user-visible app configuration. It is only
|
||||
available after the app has started.
|
||||
*/
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"golang.org/x/mobile/geom"
|
||||
)
|
||||
|
||||
// mainCalled is closed after the Go main and app.Run functions have
|
||||
// been called. This happens before an app enters the start state and
|
||||
// may happen before a window is created (on android).
|
||||
var mainCalled = make(chan struct{})
|
||||
|
||||
var (
|
||||
configCurMu sync.Mutex // guards configCur pointer, not contents
|
||||
configCur Config
|
||||
configAlt Config // used to stage new state
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Configuration is not available while the app is stopped,
|
||||
// so we begin the program with configCurMu locked. It will
|
||||
// be locked whenever !running.
|
||||
configCurMu.Lock()
|
||||
}
|
||||
|
||||
var (
|
||||
running = false
|
||||
startFuncs []func()
|
||||
stopFuncs []func()
|
||||
)
|
||||
|
||||
func stateStart(callbacks []Callbacks) {
|
||||
if running {
|
||||
return
|
||||
}
|
||||
running = true
|
||||
configCurMu.Unlock() // GetConfig is now available
|
||||
for _, cb := range callbacks {
|
||||
if cb.Start != nil {
|
||||
cb.Start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stateStop(callbacks []Callbacks) {
|
||||
if !running {
|
||||
return
|
||||
}
|
||||
running = false
|
||||
configCurMu.Lock() // GetConfig is no longer available
|
||||
for _, cb := range callbacks {
|
||||
if cb.Stop != nil {
|
||||
cb.Stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// configSwap is called to replace configCur with configAlt and if
|
||||
// necessary inform the running the app. Calls to configSwap must be
|
||||
// made after updating configAlt.
|
||||
func configSwap(callbacks []Callbacks) {
|
||||
if !running {
|
||||
// configCurMu is already locked, and no-one else
|
||||
// is around to look at configCur, so we modify it
|
||||
// directly.
|
||||
configCur = configAlt
|
||||
geom.Width, geom.Height = configCur.Width, configCur.Height // TODO: remove
|
||||
return
|
||||
}
|
||||
|
||||
configCurMu.Lock()
|
||||
old := configCur
|
||||
configCur = configAlt
|
||||
configCurMu.Unlock()
|
||||
|
||||
geom.Width, geom.Height = configCur.Width, configCur.Height // TODO: remove
|
||||
|
||||
for _, cb := range callbacks {
|
||||
if cb.Config != nil {
|
||||
cb.Config(configCur, old)
|
||||
}
|
||||
}
|
||||
}
|
37
app/x11.go
37
app/x11.go
|
@ -29,11 +29,11 @@ import (
|
|||
"golang.org/x/mobile/geom"
|
||||
)
|
||||
|
||||
var cb Callbacks
|
||||
var callbacks []Callbacks
|
||||
|
||||
func run(callbacks Callbacks) {
|
||||
func run(cbs []Callbacks) {
|
||||
runtime.LockOSThread()
|
||||
cb = callbacks
|
||||
callbacks = cbs
|
||||
C.runApp()
|
||||
}
|
||||
|
||||
|
@ -41,9 +41,12 @@ func run(callbacks Callbacks) {
|
|||
func onResize(w, h int) {
|
||||
// TODO(nigeltao): don't assume 72 DPI. DisplayWidth / DisplayWidthMM
|
||||
// is probably the best place to start looking.
|
||||
geom.PixelsPerPt = 1
|
||||
geom.Width = geom.Pt(w)
|
||||
geom.Height = geom.Pt(h)
|
||||
if geom.PixelsPerPt == 0 {
|
||||
geom.PixelsPerPt = 1
|
||||
}
|
||||
configAlt.Width = geom.Pt(w)
|
||||
configAlt.Height = geom.Pt(h)
|
||||
configSwap(callbacks)
|
||||
}
|
||||
|
||||
var touchEvents struct {
|
||||
|
@ -79,27 +82,27 @@ func onDraw() {
|
|||
pending := touchEvents.pending
|
||||
touchEvents.pending = nil
|
||||
touchEvents.Unlock()
|
||||
if cb.Touch != nil {
|
||||
for _, e := range pending {
|
||||
cb.Touch(e)
|
||||
for _, cb := range callbacks {
|
||||
if cb.Touch != nil {
|
||||
for _, e := range pending {
|
||||
cb.Touch(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cb.Draw != nil {
|
||||
cb.Draw()
|
||||
for _, cb := range callbacks {
|
||||
if cb.Draw != nil {
|
||||
cb.Draw()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//export onStart
|
||||
func onStart() {
|
||||
if cb.Start != nil {
|
||||
cb.Start()
|
||||
}
|
||||
stateInit(callbacks)
|
||||
}
|
||||
|
||||
//export onStop
|
||||
func onStop() {
|
||||
if cb.Stop != nil {
|
||||
cb.Stop()
|
||||
}
|
||||
stateStop(callbacks)
|
||||
}
|
||||
|
|
|
@ -243,7 +243,7 @@ var (
|
|||
)
|
||||
|
||||
func initAL() {
|
||||
state := app.State.(interface {
|
||||
state := app.GetConfig().(interface {
|
||||
JavaVM() unsafe.Pointer
|
||||
AndroidContext() unsafe.Pointer
|
||||
})
|
||||
|
|
|
@ -79,12 +79,8 @@ func init() {
|
|||
}
|
||||
|
||||
func initSeq() {
|
||||
vm := app.State.(interface {
|
||||
JavaVM() unsafe.Pointer
|
||||
}).JavaVM()
|
||||
classFinder := app.State.(interface {
|
||||
ClassFinder() unsafe.Pointer
|
||||
}).ClassFinder()
|
||||
vm := app.GetConfig().JavaVM()
|
||||
classFinder := app.GetConfig().ClassFinder()
|
||||
|
||||
C.init_seq(vm, classFinder)
|
||||
}
|
||||
|
|
|
@ -110,10 +110,8 @@ func (r Rectangle) String() string { return r.Min.String() + "-" + r.Max.String(
|
|||
// Not valid until app initialization has completed.
|
||||
var PixelsPerPt float32
|
||||
|
||||
// Width is the width of the device screen.
|
||||
// Not valid until app initialization has completed.
|
||||
// Width is deprecated. Use app.GetConfig().Width.
|
||||
var Width Pt
|
||||
|
||||
// Height is the height of the device screen.
|
||||
// Not valid until app initialization has completed.
|
||||
// Height is deprecated. Use app.GetConfig().Height.
|
||||
var Height Pt
|
||||
|
|
Loading…
Reference in New Issue