desktop

package
v6.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 8, 2026 License: MIT Imports: 16 Imported by: 0

README

Desktop frontend bridge

Experimental optional bridge for GWC Wasm frontends hosted by a native desktop application. The root module uses /v6. No native Wails package is imported by this package; web and desktop UIs share the portable contract.

Portable file dialogs

Application code no longer needs RPC names or generated Wails types for file pickers:

parseSelection, parseErr := desktop.OpenFile(parseContext, desktop.FileDialogOptions{
    Title: "Choose a document",
    Filters: []desktop.FileFilter{{Name: "Text", Pattern: "*.txt"}},
})
if parseErr != nil { /* unavailable, invalid, remote, cancelled context, etc. */ }
if parseSelection.Cancelled { /* operator dismissed the native picker */ }

OpenFiles, OpenDirectory and SaveFile use the same options/result contract. SaveFile only selects a destination path; it never writes a file. Paths are not permission tokens and must be validated by any later file-access service. Normal operator dismissal is Cancelled: true with no paths and no error; context cancellation/deadline is an error. Calls use a bounded five-minute wait, respect earlier caller deadlines, and cannot forcibly dismiss an OS dialog.

The package functions discover the current bridge. The same methods on Client support injected transports for testing. Client.Supports(FileDialogs) is a UI predicate; Client.Require(FileDialogs) returns a detailed preflight error. No arguments to Require means require a compatible live bridge. Unknown feature names are invalid. Ordinary web/native SSR calls return CodeUnavailable, without importing Wails. Run async operations in owned tasks, not during component render.

The portable native workflow surface also includes typed clipboard, message, window, and screen APIs. Clipboard, MessageDialogs, WindowControls, and Screens are independently policy-controlled; NativeMenus, PersistentStorage, and ReportExport reserve names for host capabilities. Parse immutable host policy with ParseFeaturePolicy("all"), "none", or a comma-separated allowlist. The effective host set is the intersection of that policy and adapter capabilities.

parsePolicy, _ := desktop.ParseFeaturePolicy("clipboard,message-dialogs")
parseHost := desktop.NewNativeHost(parseBackend, parsePolicy)
parseText, parseErr := parseHost.ClipboardRead(parseContext)
parseReply, parseErr := parseHost.ShowMessage(parseContext,
    desktop.MessageRequest{Kind: "question", Title: "Confirm", Message: "Continue?"})

For generated Wails bindings, expose NativeHost.Execute, which accepts a versioned NativeRequest and returns a NativeReply carrying structured interop.ErrorCode failures. This prevents native errors from becoming an unclassified remote exception.

Replaceable native backend

The separately versionable Wails adapter module implements FileDialogBackend. Host wiring is explicit:

parseFiles := desktop.NewFileDialogHost(wailsadapter.NewFileDialogs(), true)
// Register parseFiles as a native service and map its generated SelectPaths
// binding to desktop.FileDialogMethod in the desktop bootstrap.

The host's zero value or false opt-in denies calls before backend work. It advertises only enabled support through GetMethods, validates inputs, and returns portable error envelopes so generated-binding errors don't erase classification. Custom/fake backends implement one context-aware method; no Wails types cross this boundary. Native adapters resolve the invoking window from context, never focus.

This service's checks still apply to direct generated-binding calls that bypass the frontend SDK. They are application policy, not an OS sandbox; unrelated native code using Wails directly is outside that policy. Keep optional native imports and generated bindings in the host integration, not shared UI source.

Host setup

Serve desktop.BootstrapSource as a local external ES module (desktop.js). Before starting Wasm, import it and install an explicit generated-binding map:

import { createDesktopTransport } from "/desktop.js";
globalThis.__gwcDesktop = createDesktopTransport({
  methods: { "counter.increment": bindings.CounterService.Increment },
  topics: ["counter.progress"],
  events: runtime.Events,
  platform: "windows",
  hostVersion: "wails/v3.0.0-beta.17"
});
window.addEventListener("pagehide", () => globalThis.__gwcDesktop.close(), { once: true });

The host must serve trusted local assets and explicitly register native services. Non-RPC capabilities, currently installed native menus, can be advertised using features: ["native-menus"]. Client.Supports(NativeMenus) checks this explicit advertisement; it does not invent a menu-install RPC. RPC-backed features require their complete method set regardless of any feature advertisement. This JavaScript allowlist and capability marker are feature discovery, not a security boundary against code already executing in the privileged WebView. hostVersion describes application configuration, not an authenticated handshake.

Frontend calls and events

parseClient, parseErr := desktop.Connect()
parseValue, parseErr := desktop.Call[CounterState](parseContext, parseClient, "counter.increment")
parseStop, parseErr := desktop.Subscribe[Progress](parseContext, parseClient,
    "counter.progress", func(parseValue Progress, parseErr error) { /* update state */ })

Run calls in ui.UseTask/UseTaskCtx; return subscription cancellation from ui.UseEffect. Native/SSR and ordinary browsers without the bootstrap return interop.CodeUnavailable. An injected Transport supports native unit testing. Errors use the existing interop.Error codes (missing export, encode/decode, remote, cancelled, timeout, disposed). A closed window maps to CodeDisposed.

Call retains a 30-second ceiling, including when given context.Background. For interactive native dialogs, explicitly opt one call into a longer bounded wait:

parseResult, parseErr := desktop.CallWithTimeout[DialogResult](parseContext,
    parseClient, 5*time.Minute, "dialog.open")

The timeout must be positive and no greater than MaximumRequestTimeout (ten minutes); invalid values return interop.CodeInvalid before starting native work. Earlier caller deadlines always win. The Windows tester uses five minutes only for pickers, message dialogs, and report export; routine calls retain 30 seconds. Context cancellation forwards .cancel() to the original generated Wails request; native services must cooperate by observing ctx.Done(). Cancellation cannot reverse a completed write or necessarily dismiss an OS dialog; the user may still need to close that dialog. Closing the native Wails window also cancels its active native calls via the pinned host runtime.

The default registry allows 256 concurrent requests and 256 subscriptions. Go polls synchronous JSON envelopes rather than giving js.Func callbacks to promises. Forgotten/late results cannot invoke released Go callbacks. This bounds adapter-owned resources, not JavaScript heap retained by arbitrary third-party never-settling promises. Event bursts keep the latest value per subscription and deliver at most once per 16ms poll; do not use this channel as an audit log.

Payloads are JSON-shaped. Use strings for identifiers beyond JavaScript's exact integer range; unsafe numeric integers are rejected. Use base64 for bytes and RFC3339 strings for times. Nil is JSON null. Absent fields follow Go's JSON tags; arbitrary pointers, functions, cycles, NaN and Infinity are not bridge contracts.

Durable state

NewStorageBackend(client) implements kvstate.PersistenceBackend using the explicit storage.load/save/delete/keys methods. Its wire records carry decimal string versions/timestamps and base64 bytes. The example native service owns a bounded atomic JSON store at %AppData%/GWCWailsCounter/storage.json, guarded by a Windows OS handle lock. This is a small-app KV implementation, not SQLite or a distributed database. Versions must increase; stale/equal writes fail, and deletion preserves a tombstone version for safe recreation.

Select both the backend and its notification path explicitly:

parseOptions := kvstate.Options{
    Name: "my-desktop-app",
    Backend: desktop.NewStorageBackend(parseClient),
    Strategy: kvstate.Immediate{},
    ExternalInvalidation: true,
}
parseStop, parseErr := desktop.SubscribeStorage(parseContext, parseClient,
    parseOptions.Name, parseOnError)

The native service emits storage.changed only after a successful commit. SubscribeStorage reloads all mounted keys under the logical name, so coalescing several commits cannot lose a different key's invalidation. Reloads do not write or rebroadcast. ExternalInvalidation avoids calling the asynchronous native backend from the browser's synchronous BroadcastChannel callback. Browser bindings retain their existing default transport.

Evidence and limits

Run native contracts with go test ./desktop ./kvstate, JS contracts with node --test desktop/desktop.test.mjs, and Wasm contracts with the repository's tools/go_js_wasm_exec.bat runner and process-local js/wasm Go target variables. The isolated example requires its own build and actual native smoke tests; root tests do not cover the nested module.

See example, adapter verification, and authoritative backlog. Windows amd64/WebView2 is the current tested target. This is not yet a signed, cross-platform production support commitment.

Documentation

Overview

Package desktop provides an optional, host-independent desktop frontend bridge. Native Wails packages belong in the application's host module, never here.

Index

Constants

View Source
const (
	ClipboardWriteMethod  = "desktop.clipboard.write"
	ClipboardReadMethod   = "desktop.clipboard.read"
	MessageMethod         = "desktop.message.show"
	WindowMethod          = "desktop.window.control"
	ScreensMethod         = "desktop.screens.list"
	NativeContractVersion = 1
	ReportExportMethod    = "desktop.report.export"
	StorageLoadMethod     = "storage.load"
	StorageSaveMethod     = "storage.save"
	StorageDeleteMethod   = "storage.delete"
	StorageKeysMethod     = "storage.keys"
)
View Source
const FileDialogMethod = "desktop.files.select"

FileDialogMethod is the adapter registration name; application callers use typed methods.

View Source
const MaximumRequestTimeout = 10 * time.Minute

MaximumRequestTimeout bounds explicitly extended interactive calls.

View Source
const ProtocolVersion = 1

ProtocolVersion identifies the synchronous transport envelope contract.

View Source
const RequestTimeout = 30 * time.Second

RequestTimeout is the default call ceiling, including context.Background calls.

Variables

View Source
var BootstrapSource string

BootstrapSource is the external ES module to serve as desktop.js before Wasm.

Functions

func Call

func Call[T any](parseContext context.Context, parseClient Client, parseMethod string, parseArgs ...any) (T, error)

Call decodes one registered method's JSON response. Use strings for wide integer identifiers, base64 strings for bytes and RFC3339 strings for time values. Cancellation is cooperative and cannot undo completed native writes.

func CallWithTimeout

func CallWithTimeout[T any](parseContext context.Context, parseClient Client, parseTimeout time.Duration, parseMethod string, parseArgs ...any) (T, error)

CallWithTimeout opts one call into a positive ceiling of at most ten minutes. Earlier context deadlines still win. Use longer waits only for interactive native operations; cancellation cannot dismiss every OS dialog or undo completed writes.

func IsDesktopBuild

func IsDesktopBuild() bool

IsDesktopBuild reports the compile-time target, not permission to use a native API. An ordinary build is web/native-test mode unless gwc_desktop was explicitly set.

func Subscribe

func Subscribe[T any](parseContext context.Context, parseClient Client, parseTopic string, parseHandler func(T, error)) (func(), error)

Subscribe delivers latest-value events at most once per polling tick (16 ms). Bursts coalesce per subscription, so this API is for state/progress, not audit logs. Cancel is idempotent; a handler already executing may finish after cancellation.

func SubscribeStorage

func SubscribeStorage(parseContext context.Context, parseClient Client, parseName string, parseOnError func(error)) (func(), error)

SubscribeStorage reloads all existing kvstate bindings under a logical database name after a storage.changed commit. Reloading all keys makes topic-level burst coalescing safe. It never republishes events. Cancel it on unmount/window close. Backend selection remains explicit through kvstate.Options.Backend. Set Options.ExternalInvalidation=true to avoid browser BroadcastChannel forwarding.

Types

type Capabilities

type Capabilities struct {
	Protocol    int      `json:"protocol"`
	Platform    string   `json:"platform"`
	HostVersion string   `json:"hostVersion"`
	Methods     []string `json:"methods"`
	Topics      []string `json:"topics"`
	// Features advertises non-RPC capabilities such as installed native menus.
	// It is feature discovery, never authorization; RPC features still require methods.
	Features []Feature `json:"features,omitempty"`
}

Capabilities describes an installed bridge, not an authorization credential.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client owns calls and subscriptions; its zero value is predictably unavailable.

func Connect

func Connect() (Client, error)

Connect returns an unavailable client on native/SSR builds without loading Wails.

func NewClient

func NewClient(parseTransport Transport) Client

NewClient constructs a client with an explicit transport for testing or embedding.

func (Client) ControlWindow

func (parseClient Client) ControlWindow(parseContext context.Context, parseRequest WindowRequest) (WindowInfo, error)

ControlWindow invokes the typed window client method.

func (Client) GetCapabilities

func (parseClient Client) GetCapabilities() (Capabilities, error)

GetCapabilities validates the installed protocol before callers enable controls.

func (Client) ListScreens

func (parseClient Client) ListScreens(parseContext context.Context) ([]ScreenInfo, error)

ListScreens invokes the typed screen client method.

func (Client) OpenDirectory

func (parseClient Client) OpenDirectory(parseContext context.Context, parseOptions FileDialogOptions) (FileSelection, error)

OpenDirectory selects one directory through this explicitly injected client.

func (Client) OpenFile

func (parseClient Client) OpenFile(parseContext context.Context, parseOptions FileDialogOptions) (FileSelection, error)

OpenFile selects one file through this explicitly injected client.

func (Client) OpenFiles

func (parseClient Client) OpenFiles(parseContext context.Context, parseOptions FileDialogOptions) (FileSelection, error)

OpenFiles selects multiple files through this explicitly injected client.

func (Client) ReadClipboard

func (parseClient Client) ReadClipboard(parseContext context.Context) (string, error)

ReadClipboard invokes the typed clipboard client method.

func (Client) Require

func (parseClient Client) Require(parseFeatures ...Feature) error

Require checks a live bridge and every requested feature; it never grants host permission.

func (Client) SaveFile

func (parseClient Client) SaveFile(parseContext context.Context, parseOptions FileDialogOptions) (FileSelection, error)

SaveFile selects a save destination; no file is written by this operation.

func (Client) ShowMessage

func (parseClient Client) ShowMessage(parseContext context.Context, parseRequest MessageRequest) (MessageReply, error)

ShowMessage invokes the typed message client method.

func (Client) Supports

func (parseClient Client) Supports(parseFeatures ...Feature) bool

Supports reports effective workflow availability for optional controls.

func (Client) WriteClipboard

func (parseClient Client) WriteClipboard(parseContext context.Context, parseText string) error

WriteClipboard invokes the typed clipboard client method.

type ClipboardWriteRequest

type ClipboardWriteRequest struct {
	Text string `json:"text"`
}

ClipboardWriteRequest carries explicit text to the native clipboard.

type Feature

type Feature string

Feature identifies a portable desktop workflow, not a UI rollout flag.

const Clipboard Feature = "clipboard"

Clipboard identifies explicit text clipboard operations.

const FileDialogs Feature = "file-dialogs"

FileDialogs enables path selection, never reading or writing selected files.

const MessageDialogs Feature = "message-dialogs"

MessageDialogs identifies native information and question dialogs.

const NativeMenus Feature = "native-menus"

NativeMenus identifies native application menu and shortcut callbacks.

const PersistentStorage Feature = "persistent-storage"

PersistentStorage identifies the host-owned durable storage service.

const ReportExport Feature = "report-export"

ReportExport identifies explicit native report export.

const Screens Feature = "screens"

Screens identifies display enumeration.

const WindowControls Feature = "window-controls"

WindowControls identifies caller-owned window inspection and controls.

type FeaturePolicy

type FeaturePolicy struct {
	// contains filtered or unexported fields
}

FeaturePolicy is an immutable allowlist parsed from host configuration.

func ParseFeaturePolicy

func ParseFeaturePolicy(parseValue string) (FeaturePolicy, error)

ParseFeaturePolicy parses all, none, or a comma-separated feature allowlist.

func (FeaturePolicy) Allows

func (parsePolicy FeaturePolicy) Allows(parseFeature Feature) bool

Allows reports whether this policy permits one feature.

func (FeaturePolicy) FeatureNames

func (parsePolicy FeaturePolicy) FeatureNames() []Feature

FeatureNames returns a stable copy of allowed feature names.

func (FeaturePolicy) Intersect

func (parsePolicy FeaturePolicy) Intersect(parseFeatures []Feature) FeaturePolicy

Intersect combines policy and backend availability without granting either side new access.

type FileDialogBackend

type FileDialogBackend interface {
	SelectPaths(context.Context, FileDialogRequest) (FileSelection, error)
}

FileDialogBackend is implemented by native adapters or application test doubles. Implementations must resolve the invoking window from context, never current focus.

type FileDialogHost

type FileDialogHost struct {
	// contains filtered or unexported fields
}

FileDialogHost enforces immutable opt-in before invoking a native backend. Its zero value denies access. This policy covers this service, not unrelated host code.

func NewFileDialogHost

func NewFileDialogHost(parseBackend FileDialogBackend, isEnabled bool) *FileDialogHost

NewFileDialogHost constructs a host service with explicit file-dialog permission.

func (*FileDialogHost) GetMethods

func (parseHost *FileDialogHost) GetMethods() []string

GetMethods advertises only operations enabled in this host configuration.

func (*FileDialogHost) SelectPaths

func (parseHost *FileDialogHost) SelectPaths(parseContext context.Context, parseRequest FileDialogRequest) FileDialogReply

SelectPaths validates every direct native invocation before opening a dialog.

type FileDialogOptions

type FileDialogOptions struct {
	Title     string       `json:"title"`
	Directory string       `json:"directory"`
	Filename  string       `json:"filename"` // SaveFile only.
	Filters   []FileFilter `json:"filters"`  // File pickers only, not OpenDirectory.
}

FileDialogOptions configures a caller-owned native picker.

type FileDialogReply

type FileDialogReply struct {
	Selection FileSelection     `json:"selection"`
	Code      interop.ErrorCode `json:"code,omitempty"`
	Message   string            `json:"message,omitempty"`
}

FileDialogReply preserves portable error categories across generated bindings.

type FileDialogRequest

type FileDialogRequest struct {
	Version int               `json:"version"`
	Kind    string            `json:"kind"`
	Options FileDialogOptions `json:"options"`
}

FileDialogRequest is the versioned backend contract used by registered host services.

type FileFilter

type FileFilter struct {
	Name    string `json:"name"`
	Pattern string `json:"pattern"`
}

FileFilter describes an OS file-picker filter without backend-specific types.

type FileSelection

type FileSelection struct {
	Paths     []string `json:"paths"`
	Cancelled bool     `json:"cancelled"`
}

FileSelection distinguishes operator cancellation from successful path selection. Selecting a save path does not create or overwrite a file.

func OpenDirectory

func OpenDirectory(parseContext context.Context, parseOptions FileDialogOptions) (FileSelection, error)

OpenDirectory opens a directory picker using the connected desktop host.

func OpenFile

func OpenFile(parseContext context.Context, parseOptions FileDialogOptions) (FileSelection, error)

OpenFile opens a single-file picker using the connected desktop host.

func OpenFiles

func OpenFiles(parseContext context.Context, parseOptions FileDialogOptions) (FileSelection, error)

OpenFiles opens a multiple-file picker using the connected desktop host.

func SaveFile

func SaveFile(parseContext context.Context, parseOptions FileDialogOptions) (FileSelection, error)

SaveFile selects a save destination without creating or overwriting a file.

type MessageReply

type MessageReply struct {
	Button string `json:"button"`
}

MessageReply identifies the button selected by the operator.

type MessageRequest

type MessageRequest struct {
	Kind    string `json:"kind"`
	Title   string `json:"title"`
	Message string `json:"message"`
}

MessageRequest describes a bounded native dialog.

type NativeBackend

type NativeBackend interface {
	Features() []Feature
	ClipboardWrite(context.Context, ClipboardWriteRequest) error
	ClipboardRead(context.Context) (string, error)
	ShowMessage(context.Context, MessageRequest) (MessageReply, error)
	Window(context.Context, WindowRequest) (WindowInfo, error)
	Screens(context.Context) ([]ScreenInfo, error)
}

NativeBackend is implemented by a host adapter and must resolve caller windows from context.

type NativeHost

type NativeHost struct {
	// contains filtered or unexported fields
}

NativeHost enforces policy and backend intersection before native work.

func NewNativeHost

func NewNativeHost(parseBackend NativeBackend, parsePolicy FeaturePolicy) *NativeHost

NewNativeHost constructs a host whose effective policy is policy intersected with backend features.

func (*NativeHost) ClipboardRead

func (parseHost *NativeHost) ClipboardRead(parseContext context.Context) (string, error)

ClipboardRead performs an explicitly requested clipboard read.

func (*NativeHost) ClipboardWrite

func (parseHost *NativeHost) ClipboardWrite(parseContext context.Context, parseRequest ClipboardWriteRequest) error

ClipboardWrite performs an explicitly requested clipboard write.

func (*NativeHost) Execute

func (parseHost *NativeHost) Execute(parseContext context.Context, parseRequest NativeRequest) NativeReply

Execute handles one versioned native request and always returns a wire-safe reply.

func (*NativeHost) GetFeatures

func (parseHost *NativeHost) GetFeatures() []Feature

GetFeatures returns the effective immutable feature set.

func (*NativeHost) GetMethods

func (parseHost *NativeHost) GetMethods() []string

GetMethods returns only methods enabled by effective policy.

func (*NativeHost) ListScreens

func (parseHost *NativeHost) ListScreens(parseContext context.Context) ([]ScreenInfo, error)

ListScreens returns typed display information.

func (*NativeHost) Require

func (parseHost *NativeHost) Require(parseFeature Feature) error

Require checks policy and backend support for one feature.

func (*NativeHost) ShowMessage

func (parseHost *NativeHost) ShowMessage(parseContext context.Context, parseRequest MessageRequest) (MessageReply, error)

ShowMessage displays one typed native dialog.

func (*NativeHost) WindowControl

func (parseHost *NativeHost) WindowControl(parseContext context.Context, parseRequest WindowRequest) (WindowInfo, error)

WindowControl performs one typed caller-window operation.

type NativeReply

type NativeReply struct {
	Version int               `json:"version"`
	Data    json.RawMessage   `json:"data,omitempty"`
	Code    interop.ErrorCode `json:"code,omitempty"`
	Message string            `json:"message,omitempty"`
}

NativeReply is the structured result envelope; native failures never rely on thrown errors.

type NativeRequest

type NativeRequest struct {
	Version int             `json:"version"`
	Method  string          `json:"method"`
	Args    json.RawMessage `json:"args"`
}

NativeRequest is the versioned envelope used by generated host bindings.

type Reply

type Reply struct {
	Done    bool              `json:"done"`
	Data    json.RawMessage   `json:"data"`
	Code    interop.ErrorCode `json:"code,omitempty"`
	Message string            `json:"message,omitempty"`
}

Reply is a synchronously polled request/event envelope; Data is JSON, not JS handles.

type ScreenInfo

type ScreenInfo struct {
	ID      string  `json:"id"`
	Name    string  `json:"name"`
	Primary bool    `json:"primary"`
	Scale   float32 `json:"scale"`
	X       int     `json:"x"`
	Y       int     `json:"y"`
	Width   int     `json:"width"`
	Height  int     `json:"height"`
}

ScreenInfo reports a display without exposing backend-specific screen objects.

type StorageBackend

type StorageBackend struct {
	// contains filtered or unexported fields
}

StorageBackend adapts the named desktop storage methods to kvstate.

func NewStorageBackend

func NewStorageBackend(parseClient Client) StorageBackend

NewStorageBackend constructs a service-backed kvstate persistence backend.

func (StorageBackend) Delete

func (parseBackend StorageBackend) Delete(parseContext context.Context, parseKey string) error

Delete creates a durable tombstone for one key.

func (StorageBackend) Keys

func (parseBackend StorageBackend) Keys(parseContext context.Context) ([]string, error)

Keys returns live keys in the native store.

func (StorageBackend) Load

func (parseBackend StorageBackend) Load(parseContext context.Context, parseKey string) (kvstate.Record, bool, error)

Load retrieves one record and reports whether the key exists.

func (StorageBackend) Save

func (parseBackend StorageBackend) Save(parseContext context.Context, parseRecord kvstate.Record) error

Save durably writes one record through the native service.

type StorageCommit

type StorageCommit struct {
	Key     string `json:"key"`
	Version string `json:"version"`
	Deleted bool   `json:"deleted"`
}

StorageCommit describes a successful durable mutation for event forwarding.

type StorageWireRecord

type StorageWireRecord struct {
	Key       string `json:"key"`
	Value     string `json:"value"`
	Version   string `json:"version"`
	UpdatedAt string `json:"updatedAt"`
}

StorageWireRecord is the JSON-safe storage record exchanged with a native host. Wide integers are decimal strings and bytes are base64 strings by contract.

type Transport

type Transport interface {
	Capabilities() (Capabilities, error)
	Start(string, json.RawMessage) (string, error)
	Poll(string) (Reply, error)
	Cancel(string) error
	Listen(string) (string, error)
	Next(string) (Reply, error)
	Unlisten(string) error
}

Transport can be injected in native tests. Methods must return promptly and serialize access internally. Cancel must forget requests even if native work stalls.

type WindowInfo

type WindowInfo struct {
	ID         string `json:"id"`
	Name       string `json:"name"`
	Width      int    `json:"width"`
	Height     int    `json:"height"`
	Maximised  bool   `json:"maximised"`
	Fullscreen bool   `json:"fullscreen"`
}

WindowInfo reports stable caller-window metadata.

type WindowRequest

type WindowRequest struct {
	Action string `json:"action"`
	Width  int    `json:"width,omitempty"`
	Height int    `json:"height,omitempty"`
}

WindowRequest describes one caller-owned window operation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL