mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-07 15:13:51 +08:00
- 单次快捷键可重新唤起停驻 AI 子窗,并过滤重复键盘事件 - 打开 AI 设置前原子隐藏子窗,避免设置窗口被遮挡 - 用可见性版本阻止延迟隐藏或设置事件覆盖新焦点 - 拒绝复用终态子进程,并恢复失败的附加与关闭操作 - 串行展示、隐藏和终态退出,消除关闭门闩并发竞态 - 增加原生窗口生命周期、结果回滚和焦点恢复回归测试
169 lines
5.6 KiB
Go
169 lines
5.6 KiB
Go
package nativewindow
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
// DetachedWindowArgument selects the native detached-window child mode.
|
|
DetachedWindowArgument = "--detached-window"
|
|
|
|
HeaderToken = "X-GoNavi-Detached-Token"
|
|
HeaderWindowID = "X-GoNavi-Detached-Window-ID"
|
|
|
|
BootstrapPath = "/__gonavi/detached/bootstrap"
|
|
ActionPath = "/__gonavi/detached/action"
|
|
ControlPath = "/__gonavi/detached/control"
|
|
HostStatePath = "/__gonavi/detached/host-state"
|
|
CommandStatePath = "/__gonavi/detached/command-state"
|
|
RuntimePath = "/__gonavi/detached-runtime.js"
|
|
InvokePath = "/__gonavi/api/invoke"
|
|
EventsPath = "/__gonavi/events"
|
|
|
|
MainEventName = "gonavi:native-detached-event"
|
|
CommandEventName = "gonavi:native-detached-command"
|
|
// GracefulCloseRequestEventName is dispatched inside a detached WebView so
|
|
// React can flush state before the native child process exits.
|
|
GracefulCloseRequestEventName = "gonavi:native-detached-request-close"
|
|
// GracefulHideRequestEventName asks an already-mounted detached frontend to
|
|
// flush its state before parking the native window without exiting its
|
|
// process. The visibility revision prevents a late hide from winning over a
|
|
// newer focus request.
|
|
GracefulHideRequestEventName = "gonavi:native-detached-request-hide"
|
|
|
|
ExitReasonRequested = "requested"
|
|
ExitReasonWindowClosed = "window-closed"
|
|
ExitReasonAttached = "attached"
|
|
ExitReasonParentShutdown = "parent-shutdown"
|
|
ExitReasonProcessError = "process-error"
|
|
)
|
|
|
|
const (
|
|
defaultWindowWidth = 1080
|
|
defaultWindowHeight = 720
|
|
// Detached query results can be substantially larger than ordinary RPC
|
|
// payloads. Keep one shared ceiling for child actions and parent responses.
|
|
maxDetachedJSONBytes int64 = 512 << 20
|
|
maxDetachedSSEEventBytes = maxDetachedJSONBytes + (1 << 20)
|
|
)
|
|
|
|
// OpenRequest describes one independently movable native window. X and Y use
|
|
// virtual-desktop coordinates and deliberately allow negative values.
|
|
type OpenRequest struct {
|
|
ID string `json:"id,omitempty"`
|
|
Kind string `json:"kind"`
|
|
Title string `json:"title"`
|
|
Payload any `json:"payload,omitempty"`
|
|
X int `json:"x"`
|
|
Y int `json:"y"`
|
|
Width int `json:"width"`
|
|
Height int `json:"height"`
|
|
}
|
|
|
|
// WindowBounds uses the browser/Wails virtual desktop coordinate system with
|
|
// the primary display's top-left as the origin. Negative coordinates remain
|
|
// valid for displays arranged to the left or above the primary display.
|
|
type WindowBounds struct {
|
|
X int `json:"x"`
|
|
Y int `json:"y"`
|
|
Width int `json:"width"`
|
|
Height int `json:"height"`
|
|
}
|
|
|
|
// WindowInfo is the serialisable view of a registered child process.
|
|
type WindowInfo struct {
|
|
ID string `json:"id"`
|
|
Kind string `json:"kind"`
|
|
Title string `json:"title"`
|
|
X int `json:"x"`
|
|
Y int `json:"y"`
|
|
Width int `json:"width"`
|
|
Height int `json:"height"`
|
|
PID int `json:"pid,omitempty"`
|
|
OpenedAt int64 `json:"openedAt"`
|
|
Ready bool `json:"ready"`
|
|
CloseSent bool `json:"closeSent"`
|
|
Hidden bool `json:"hidden,omitempty"`
|
|
}
|
|
|
|
// Bootstrap is fetched by the child after Wails has installed its native
|
|
// runtime and bindings.
|
|
type Bootstrap struct {
|
|
ID string `json:"id"`
|
|
Kind string `json:"kind"`
|
|
Title string `json:"title"`
|
|
Payload any `json:"payload,omitempty"`
|
|
ActionRevision int64 `json:"actionRevision,omitempty"`
|
|
}
|
|
|
|
// OperationResult is returned by the Wails-bound Manager commands.
|
|
type OperationResult struct {
|
|
Success bool `json:"success"`
|
|
Message string `json:"message,omitempty"`
|
|
ID string `json:"id,omitempty"`
|
|
Bounds *WindowBounds `json:"bounds,omitempty"`
|
|
VisibilityRevision uint64 `json:"visibilityRevision,omitempty"`
|
|
// Applied is set only for revisioned child actions. A nil value preserves
|
|
// compatibility with ordinary manager/control results and older parents.
|
|
Applied *bool `json:"applied,omitempty"`
|
|
}
|
|
|
|
// HostStateRequest carries main-window state that an active detached child
|
|
// needs to follow. Revision is strictly monotonic per child window ID.
|
|
type HostStateRequest struct {
|
|
ID string `json:"id"`
|
|
Revision int64 `json:"revision"`
|
|
StoreState map[string]any `json:"storeState"`
|
|
}
|
|
|
|
type hostStatePayload struct {
|
|
Revision int64 `json:"revision"`
|
|
StoreState map[string]any `json:"storeState"`
|
|
}
|
|
|
|
// Event is emitted to the main Wails window. Action mirrors the detached HTTP
|
|
// action protocol so the frontend can use one reducer for child messages and
|
|
// process-exit notifications.
|
|
type Event struct {
|
|
ID string `json:"id"`
|
|
Kind string `json:"kind"`
|
|
Action string `json:"action"`
|
|
Payload any `json:"payload,omitempty"`
|
|
}
|
|
|
|
type actionRequest struct {
|
|
Action string `json:"action"`
|
|
Payload any `json:"payload,omitempty"`
|
|
}
|
|
|
|
type controlRequest struct {
|
|
Action string `json:"action"`
|
|
ID string `json:"id,omitempty"`
|
|
Request OpenRequest `json:"request,omitempty"`
|
|
}
|
|
|
|
type childCommand struct {
|
|
ID string `json:"id"`
|
|
Action string `json:"action"`
|
|
Reason string `json:"reason,omitempty"`
|
|
Payload any `json:"payload,omitempty"`
|
|
}
|
|
|
|
func normalizeOpenRequest(request OpenRequest) OpenRequest {
|
|
request.Kind = strings.TrimSpace(request.Kind)
|
|
request.Title = strings.TrimSpace(request.Title)
|
|
if request.Kind == "" {
|
|
request.Kind = "workbench"
|
|
}
|
|
if request.Title == "" {
|
|
request.Title = "GoNavi"
|
|
}
|
|
if request.Width <= 0 {
|
|
request.Width = defaultWindowWidth
|
|
}
|
|
if request.Height <= 0 {
|
|
request.Height = defaultWindowHeight
|
|
}
|
|
return request
|
|
}
|