mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 09:55:40 +00:00
app/internal/window: [android] re-apply view state lost on rotate etc.
Android can re-create our Activity and GioView at any time, losing view and activity state such as the current cursor. Further, setting state while there is no GioView attached is lost. Track the current and unapplied state, and apply it when a GioView is available. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -71,11 +71,20 @@ type window struct {
|
|||||||
stage system.Stage
|
stage system.Stage
|
||||||
started bool
|
started bool
|
||||||
|
|
||||||
|
state, newState windowState
|
||||||
|
|
||||||
|
// mu protects the fields following it.
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
win *C.ANativeWindow
|
win *C.ANativeWindow
|
||||||
animating bool
|
animating bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// windowState tracks the View or Activity specific state lost when Android
|
||||||
|
// re-creates our Activity.
|
||||||
|
type windowState struct {
|
||||||
|
cursor *pointer.CursorName
|
||||||
|
}
|
||||||
|
|
||||||
// gioView hold cached JNI methods for GioView.
|
// gioView hold cached JNI methods for GioView.
|
||||||
var gioView struct {
|
var gioView struct {
|
||||||
once sync.Once
|
once sync.Once
|
||||||
@@ -118,8 +127,12 @@ var android struct {
|
|||||||
mwakeupMainThread C.jmethodID
|
mwakeupMainThread C.jmethodID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// view maps from GioView JNI refenreces to windows.
|
||||||
var views = make(map[C.jlong]*window)
|
var views = make(map[C.jlong]*window)
|
||||||
|
|
||||||
|
// windows maps from Callbacks to windows
|
||||||
|
var windows = make(map[Callbacks]*window)
|
||||||
|
|
||||||
var mainWindow = newWindowRendezvous()
|
var mainWindow = newWindowRendezvous()
|
||||||
|
|
||||||
var mainFuncs = make(chan func(env *C.JNIEnv), 1)
|
var mainFuncs = make(chan func(env *C.JNIEnv), 1)
|
||||||
@@ -209,15 +222,20 @@ func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.j
|
|||||||
m.setCursor = getMethodID(env, class, "setCursor", "(I)V")
|
m.setCursor = getMethodID(env, class, "setCursor", "(I)V")
|
||||||
})
|
})
|
||||||
view = C.gio_jni_NewGlobalRef(env, view)
|
view = C.gio_jni_NewGlobalRef(env, view)
|
||||||
w := &window{
|
|
||||||
view: view,
|
|
||||||
}
|
|
||||||
wopts := <-mainWindow.out
|
wopts := <-mainWindow.out
|
||||||
w.callbacks = wopts.window
|
w, ok := windows[wopts.window]
|
||||||
|
if !ok {
|
||||||
|
w = &window{
|
||||||
|
callbacks: wopts.window,
|
||||||
|
}
|
||||||
|
windows[wopts.window] = w
|
||||||
|
}
|
||||||
w.callbacks.SetDriver(w)
|
w.callbacks.SetDriver(w)
|
||||||
|
w.view = view
|
||||||
handle := C.jlong(view)
|
handle := C.jlong(view)
|
||||||
views[handle] = w
|
views[handle] = w
|
||||||
w.loadConfig(env, class)
|
w.loadConfig(env, class)
|
||||||
|
applyStateDiff(env, view, windowState{}, w.state)
|
||||||
w.setStage(system.StagePaused)
|
w.setStage(system.StagePaused)
|
||||||
w.callbacks.Event(ViewEvent{View: uintptr(view)})
|
w.callbacks.Event(ViewEvent{View: uintptr(view)})
|
||||||
return handle
|
return handle
|
||||||
@@ -659,6 +677,33 @@ func (w *window) ReadClipboard() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) SetCursor(name pointer.CursorName) {
|
func (w *window) SetCursor(name pointer.CursorName) {
|
||||||
|
w.setState(func(state *windowState) {
|
||||||
|
state.cursor = &name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// setState adjust the window state on the main thread.
|
||||||
|
func (w *window) setState(f func(state *windowState)) {
|
||||||
|
runOnMain(func(env *C.JNIEnv) {
|
||||||
|
f(&w.newState)
|
||||||
|
if w.view == 0 {
|
||||||
|
// No View attached. The state will be applied at next onCreateView.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
old := w.state
|
||||||
|
state := w.newState
|
||||||
|
applyStateDiff(env, w.view, old, state)
|
||||||
|
w.state = state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyStateDiff(env *C.JNIEnv, view C.jobject, old, state windowState) {
|
||||||
|
if state.cursor != nil && old.cursor != state.cursor {
|
||||||
|
setCursor(env, view, *state.cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setCursor(env *C.JNIEnv, view C.jobject, name pointer.CursorName) {
|
||||||
var curID int
|
var curID int
|
||||||
switch name {
|
switch name {
|
||||||
default:
|
default:
|
||||||
@@ -678,9 +723,7 @@ func (w *window) SetCursor(name pointer.CursorName) {
|
|||||||
case pointer.CursorNone:
|
case pointer.CursorNone:
|
||||||
curID = 0 // TYPE_NULL
|
curID = 0 // TYPE_NULL
|
||||||
}
|
}
|
||||||
runOnMain(func(env *C.JNIEnv) {
|
callVoidMethod(env, view, gioView.setCursor, jvalue(curID))
|
||||||
callVoidMethod(env, w.view, gioView.setCursor, jvalue(curID))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the window. Not implemented for Android.
|
// Close the window. Not implemented for Android.
|
||||||
|
|||||||
Reference in New Issue
Block a user