~eliasnaur/gio

90688fdd175f2a535382abd77df8663231b862b2 — Inkeliz 9 months ago b1dba5f
app,io/system: [API] add StageInactive when window is not in focus

Now, Gio will send one system.StageEvent with system.StageInactive when
the window is not active. It is implemented on macOS and Windows.

This change is not fully backward compatible, if your code compares
the Stage (`stage < system.StageRunning`), you need to consider
the new system.StageInactive.

Signed-off-by: inkeliz <inkeliz@inkeliz.com>
M app/internal/windows/windows.go => app/internal/windows/windows.go +1 -0
@@ 243,6 243,7 @@ const (
	WM_MOUSEMOVE            = 0x0200
	WM_MOUSEWHEEL           = 0x020A
	WM_MOUSEHWHEEL          = 0x020E
	WM_NCACTIVATE           = 0x0086
	WM_NCHITTEST            = 0x0084
	WM_PAINT                = 0x000F
	WM_QUIT                 = 0x0012

M app/os_android.go => app/os_android.go +3 -3
@@ 552,7 552,7 @@ func Java_org_gioui_GioView_onLowMemory(env *C.JNIEnv, class C.jclass) {
func Java_org_gioui_GioView_onConfigurationChanged(env *C.JNIEnv, class C.jclass, view C.jlong) {
	w := cgo.Handle(view).Value().(*window)
	w.loadConfig(env, class)
	if w.stage >= system.StageRunning {
	if w.stage >= system.StageInactive {
		w.draw(env, true)
	}
}


@@ 563,7 563,7 @@ func Java_org_gioui_GioView_onFrameCallback(env *C.JNIEnv, class C.jclass, view 
	if !exist {
		return
	}
	if w.stage < system.StageRunning {
	if w.stage < system.StageInactive {
		return
	}
	if w.animating {


@@ 596,7 596,7 @@ func Java_org_gioui_GioView_onWindowInsets(env *C.JNIEnv, class C.jclass, view C
		left:   int(left),
		right:  int(right),
	}
	if w.stage >= system.StageRunning {
	if w.stage >= system.StageInactive {
		w.draw(env, true)
	}
}

M app/os_macos.go => app/os_macos.go +7 -0
@@ 561,6 561,13 @@ func gio_onDraw(view C.CFTypeRef) {
func gio_onFocus(view C.CFTypeRef, focus C.int) {
	w := mustView(view)
	w.w.Event(key.FocusEvent{Focus: focus == 1})
	if w.stage >= system.StageInactive {
		if focus == 0 {
			w.setStage(system.StageInactive)
		} else {
			w.setStage(system.StageRunning)
		}
	}
	w.SetCursor(w.cursor)
}


M app/os_windows.go => app/os_windows.go +8 -0
@@ 283,6 283,14 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
	case windows.WM_KILLFOCUS:
		w.focused = false
		w.w.Event(key.FocusEvent{Focus: false})
	case windows.WM_NCACTIVATE:
		if w.stage >= system.StageInactive {
			if wParam == windows.TRUE {
				w.setStage(system.StageRunning)
			} else {
				w.setStage(system.StageInactive)
			}
		}
	case windows.WM_NCHITTEST:
		if w.config.Decorated {
			// Let the system handle it.

M app/window.go => app/window.go +3 -3
@@ 429,7 429,7 @@ func (w *Window) driverDefer(f func(d driver)) {

func (w *Window) updateAnimation(d driver) {
	animate := false
	if w.stage >= system.StageRunning && w.hasNextFrame {
	if w.stage >= system.StageInactive && w.hasNextFrame {
		if dt := time.Until(w.nextFrame); dt <= 0 {
			animate = true
		} else {


@@ 829,7 829,7 @@ func (w *Window) processEvent(d driver, e event.Event) bool {
	}
	switch e2 := e.(type) {
	case system.StageEvent:
		if e2.Stage < system.StageRunning {
		if e2.Stage < system.StageInactive {
			if w.gpu != nil {
				w.ctx.Lock()
				w.gpu.Release()


@@ 845,7 845,7 @@ func (w *Window) processEvent(d driver, e event.Event) bool {
		if e2.Size == (image.Point{}) {
			panic(errors.New("internal error: zero-sized Draw"))
		}
		if w.stage < system.StageRunning {
		if w.stage < system.StageInactive {
			// No drawing if not visible.
			break
		}

M io/system/system.go => io/system/system.go +10 -3
@@ 59,17 59,24 @@ type StageEvent struct {
type Stage uint8

const (
	// StagePaused is the Stage for inactive Windows.
	// Inactive Windows don't receive FrameEvents.
	// StagePaused is the stage for windows that have no on-screen representation.
	// Paused windows don't receive FrameEvent.
	StagePaused Stage = iota
	// StateRunning is for active Windows.
	// StageInactive is the stage for windows that are visible, but not active.
	// Inactive windows receive FrameEvent.
	StageInactive
	// StageRunning is for active and visible Windows.
	// Running windows receive FrameEvent.
	StageRunning
)

// String implements fmt.Stringer.
func (l Stage) String() string {
	switch l {
	case StagePaused:
		return "StagePaused"
	case StageInactive:
		return "StageInactive"
	case StageRunning:
		return "StageRunning"
	default: