Files
gio-patched/app/app.go
T
CoyAce 99647591f6 app: [Android] delete redundant dataDirChan
since dataDir() must call after main(), it's redundant to use channel to send path

Signed-off-by: CoyAce <AkeyCoy@gmail.com>
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2026-01-07 13:10:33 +01:00

200 lines
5.2 KiB
Go

// SPDX-License-Identifier: Unlicense OR MIT
package app
import (
"gioui.org/io/event"
"golang.org/x/net/idna"
"image"
"net/url"
"os"
"path/filepath"
"strings"
"time"
"gioui.org/io/input"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/unit"
)
// extraArgs contains extra arguments to append to
// os.Args. The arguments are separated with |.
// Useful for running programs on mobiles where the
// command line is not available.
// Set with the go linker flag -X.
var extraArgs string
// ID is the app id exposed to the platform.
//
// On Android ID is the package property of AndroidManifest.xml,
// on iOS ID is the CFBundleIdentifier of the app Info.plist,
// on Wayland it is the toplevel app_id,
// on X11 it is the X11 XClassHint.
//
// ID is set by the [gioui.org/cmd/gogio] tool or manually with the -X linker flag. For example,
//
// go build -ldflags="-X 'gioui.org/app.ID=org.gioui.example.Kitchen'" .
//
// Note that ID is treated as a constant, and that changing it at runtime
// is not supported. The default value of ID is filepath.Base(os.Args[0]).
var ID = ""
// A FrameEvent requests a new frame in the form of a list of
// operations that describes the window content.
type FrameEvent struct {
// Now is the current animation. Use Now instead of time.Now to
// synchronize animation and to avoid the time.Now call overhead.
Now time.Time
// Metric converts device independent dp and sp to device pixels.
Metric unit.Metric
// Size is the dimensions of the window.
Size image.Point
// Insets represent the space occupied by system decorations and controls.
Insets Insets
// Frame completes the FrameEvent by drawing the graphical operations
// from ops into the window.
Frame func(frame *op.Ops)
// Source is the interface between the window and widgets.
Source input.Source
}
// URLEvent is generated for external requests to open a URL. Unlike window specific events,
// it is delivered through the [Events] iterator.
//
// In order to receive URLEvents the program must register one or more URL schemes. A scheme can
// be registered using gogio, with the `-schemes` flag.
type URLEvent struct {
URL *url.URL
}
// ViewEvent provides handles to the underlying window objects for the
// current display protocol.
type ViewEvent interface {
implementsViewEvent()
ImplementsEvent()
// Valid will return true when the ViewEvent does contains valid handles.
// If a window receives an invalid ViewEvent, it should deinitialize any
// state referring to handles from a previous ViewEvent.
Valid() bool
}
// Insets is the space taken up by
// system decoration such as translucent
// system bars and software keyboards.
type Insets struct {
// Values are in pixels.
Top, Bottom, Left, Right unit.Dp
}
// NewContext is shorthand for
//
// layout.Context{
// Ops: ops,
// Now: e.Now,
// Source: e.Source,
// Metric: e.Metric,
// Constraints: layout.Exact(e.Size),
// }
//
// NewContext calls ops.Reset and adjusts ops for e.Insets.
func NewContext(ops *op.Ops, e FrameEvent) layout.Context {
ops.Reset()
size := e.Size
if e.Insets != (Insets{}) {
left := e.Metric.Dp(e.Insets.Left)
top := e.Metric.Dp(e.Insets.Top)
op.Offset(image.Point{
X: left,
Y: top,
}).Add(ops)
size.X -= left + e.Metric.Dp(e.Insets.Right)
size.Y -= top + e.Metric.Dp(e.Insets.Bottom)
}
return layout.Context{
Ops: ops,
Now: e.Now,
Source: e.Source,
Metric: e.Metric,
Constraints: layout.Exact(size),
}
}
// DataDir returns a path to use for application-specific
// configuration data.
// On desktop systems, DataDir use os.UserConfigDir.
// On iOS NSDocumentDirectory is queried.
// For Android Context.getFilesDir is used.
//
// BUG: On Android, DataDir panics if called before main.
func DataDir() (string, error) {
return dataDir()
}
// Main must be called last from the program main function.
// On most platforms Main blocks forever, for Android and
// iOS it returns immediately to give control of the main
// thread back to the system.
//
// Calling Main is necessary because some operating systems
// require control of the main thread of the program for
// running windows.
func Main() {
osMain()
}
// Events is an iterator that yields events that are not specific to any window,
// such as [URLEvent]. It never returns.
//
// Events must be called by the main goroutine, and replaces the
// call to [Main].
func Events(yield func(event.Event) bool) {
yieldGlobalEvent = yield
osMain()
}
var yieldGlobalEvent func(evt event.Event) bool
func processGlobalEvent(evt event.Event) {
if yieldGlobalEvent == nil {
return
}
if !yieldGlobalEvent(evt) {
yieldGlobalEvent = nil
}
}
func (FrameEvent) ImplementsEvent() {}
func (URLEvent) ImplementsEvent() {}
func init() {
if extraArgs != "" {
args := strings.Split(extraArgs, "|")
os.Args = append(os.Args, args...)
}
if ID == "" {
ID = filepath.Base(os.Args[0])
}
}
// newURLEvent creates a URLEvent from a raw URL string, handling Punycode decoding.
func newURLEvent(rawurl string) (URLEvent, error) {
u, err := url.Parse(rawurl)
if err != nil {
return URLEvent{}, err
}
u.Host, err = idna.Punycode.ToUnicode(u.Hostname())
if err != nil {
return URLEvent{}, err
}
u, err = url.Parse(u.String())
if err != nil {
return URLEvent{}, err
}
return URLEvent{URL: u}, nil
}