27 Commits

Author SHA1 Message Date
Chris Waldon 03a1ada8ac go.*: update to gio v0.8.0
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
2025-01-14 10:57:56 -05:00
Chris Waldon eb9fbc797e go.*: update to Gio v0.7.1
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
2024-07-16 20:39:39 -04:00
Chris Waldon d0d7f84d0e go.*: update to Gio v0.7.0
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
2024-06-17 13:29:39 -04:00
zhengrui 6465f30f98 gogio: [Android] add -targetsdk flag to specify the target SDK level
Fixes: https://todo.sr.ht/~eliasnaur/gio/582
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-06-07 11:36:00 +02:00
Elias Naur ddde16a09e gogio: use buildmode exe directly instead of a Objective-C main function
Using buildmode exe directly is faster to build, avoids the runMain
linker mode hack, and leaves more control to Gio instead of gogio's
synthetic main function.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-06-02 13:15:22 +02:00
Elias Naur c9121dcb8c go.*,gogio: update to Gio 0.6.0
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-04-14 08:34:39 +02:00
Aman Karmani b9c6c3edf0 gogio: [tvOS] bump minSDK to 11.0
References: https://todo.sr.ht/~eliasnaur/gio/567
Signed-off-by: Aman Karmani <aman@tmm1.net>
2024-03-06 21:51:32 +00:00
Elias Naur aa41850405 gogio: support explicit version codes through a fourth version field
As suggested in review, explicitly specifying the version code with
-version major.minor.patch.versioncode provides more flexibility than
the a version code implied from the major, minor, patch fields.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-01-28 11:51:06 -05:00
Elias Naur a24a395e5f gogio: [iOS] link with -lresolv
Since Go 1.20 c-shared object files may lack a reference to the resolv
library and it must be added manually to the linking step.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-01-28 11:51:06 -05:00
Elias Naur 7a117566ca gogio: replace deprecated calls
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-01-28 11:51:06 -05:00
Elias Naur cb72b91a92 gogio: change -version parameter to accept semver versions
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-01-15 11:41:30 -05:00
Elias Naur 607a9e37c5 gogio: set gioui.org/app.ID in addition to the log package's appID
app.ID is documented to be set by the gogio tool, but never was.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2023-12-11 18:56:04 -06:00
Chris Waldon 36ef219a61 gogio: skip e2e test on macOS and other unsupported platforms
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
2023-11-20 14:55:53 -05:00
Masala abc34cf117 gogio: add -tags to 'go list' command
Signed-off-by: Masala <masala@riseup.net>
2023-10-01 08:50:17 -05:00
Elias Naur 7cb98d0557 gogio: remove fallback for missing GOOS=ios support in Go <= 1.15
Go 1.16 is already old, and the GOOS detection code fails for me on
Nix:

$ go run gioui.org/cmd/gogio -target ios ../gio-example/kitchen
gogio: go tool dist list failed: go tool dist: FAILED: not a Git repo; must put a VERSION file in $GOROOT

The error message points to a Nix packaging issue, but removing the
fallback is easier to fix.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2023-08-22 10:59:48 -06:00
inkeliz 4128f253e8 gogio: [macOS] add notarizing
Now, it's possible to notarize the app, using -notaryid,
-notarypass and -notaryteamid flags. Those flags are
similar to -signkey and -signpass.

Signed-off-by: inkeliz <inkeliz@inkeliz.com>
2023-07-11 20:11:57 +01:00
inkeliz 42b1cd0f6c gogio: [macOS] fix signature on network-drives
Previously, gogio creates the `.app` and then generates
the signature.

Now, it will generate the `.app` on the temporary folder,
then move it. It also generates one `.zip` folder, which
will be used in the next patch.

Signed-off-by: inkeliz <inkeliz@inkeliz.com>
2023-07-11 19:41:47 +01:00
Chris Waldon 7b925a6c25 ci: use working debian image
Builds.sr.ht is having problems with the debian/testing image because it is
switching which concrete debian release it points at. In the meantime, we can
use use the same release as before by a concrete name.

Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
2023-07-07 15:41:45 -04:00
Tobias Gesellchen 940364d3e9 gogio: add ldflags support for the macos build
Signed-off-by: Tobias Gesellchen <tobias@gesellix.de>
2023-07-01 09:01:52 +02:00
gedw99 0a86898b41 gogio: update keytool path for newer JDK
Signed-off-by: gedw99 <gedw99@gmail.com>
2023-05-02 12:20:08 -06:00
Elias Naur 78da7b9864 go.mod: bump Go to 1.19
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2023-04-14 14:08:09 -06:00
Ilia Demianenko cf291ca3bd gogio: add support for setting app name via command line
This allows the app name to have spaces and other characters not allowed in Go modules.

Signed-off-by: Ilia Demianenko <ilia.demianenko@gmail.com>
2023-04-14 13:50:53 -06:00
Inkeliz 5c14d1ba64 gogio: [MacOS] add MacOS .app compilation
This patch is a initial implementation to make
`.app` file. It supports custom icons and sign.

Signed-off-by: Inkeliz <inkeliz@inkeliz.com>
2023-01-27 20:41:37 -06:00
Elias Naur 02068d6340 cmd/svg2gio: add utility for converting SVG files to Gio
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-08-18 10:09:36 +02:00
Elias Naur 2edf599beb gogio: [Android] map the wakelock permission to WAKE_LOCK
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-08-01 20:19:51 +02:00
a 9768b95616 Revert "gogio: refuse compilation with additional arguments"
Build arguments are passed to the program, which is useful for
platforms where there is no other way to pas them (Android, iOS).

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-08-01 20:19:39 +02:00
Chris Waldon ecebd405a7 gogio: implement custom rendering test
This commit adds an end to end test for the custom rendering
use-case. I confirmed that the new test failed when custom
rendering frame lifecycle was broken, and succeeds now.

However, the old X11 tests started failing when the new
one started passing. I'm not sure how they interfere with
one another, but I'm out of time to investigate.

Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
2022-06-28 21:57:19 +02:00
19 changed files with 1095 additions and 298 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ environment:
tasks:
- install_go: |
mkdir -p /home/build/sdk
curl -s https://dl.google.com/go/go1.17.7.linux-amd64.tar.gz | tar -C /home/build/sdk -xzf -
curl -s https://dl.google.com/go/go1.19.8.linux-amd64.tar.gz | tar -C /home/build/sdk -xzf -
- prepare_toolchain: |
mkdir -p $APPLE_TOOLCHAIN_ROOT
cd $APPLE_TOOLCHAIN_ROOT
+1 -1
View File
@@ -16,7 +16,7 @@ environment:
tasks:
- install_go: |
mkdir -p /home/build/sdk
curl https://dl.google.com/go/go1.17.7.freebsd-amd64.tar.gz | tar -C /home/build/sdk -xzf -
curl https://dl.google.com/go/go1.19.8.freebsd-amd64.tar.gz | tar -C /home/build/sdk -xzf -
- test_cmd: |
cd gio-cmd
go test ./...
+2 -2
View File
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: Unlicense OR MIT
image: debian/testing
image: debian/bookworm
packages:
- curl
- pkg-config
@@ -39,7 +39,7 @@ secrets:
tasks:
- install_go: |
mkdir -p /home/build/sdk
curl -s https://dl.google.com/go/go1.17.7.linux-amd64.tar.gz | tar -C /home/build/sdk -xzf -
curl -s https://dl.google.com/go/go1.19.8.linux-amd64.tar.gz | tar -C /home/build/sdk -xzf -
- check_gofmt: |
cd gio-cmd
test -z "$(gofmt -s -l .)"
+1 -1
View File
@@ -10,7 +10,7 @@ environment:
tasks:
- install_go: |
mkdir -p /home/build/sdk
curl https://dl.google.com/go/go1.17.7.src.tar.gz | tar -C /home/build/sdk -xzf -
curl https://dl.google.com/go/go1.19.8.src.tar.gz | tar -C /home/build/sdk -xzf -
cd /home/build/sdk/go/src
./make.bash
- test_cmd: |
+12 -15
View File
@@ -1,31 +1,28 @@
module gioui.org/cmd
go 1.17
go 1.21
require (
gioui.org v0.0.0-20220628163331-e21c665e70ae
gioui.org v0.8.0
github.com/akavel/rsrc v0.10.1
github.com/chromedp/cdproto v0.0.0-20191114225735-6626966fbae4
github.com/chromedp/chromedp v0.5.2
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
golang.org/x/text v0.3.7
golang.org/x/tools v0.1.0
golang.org/x/image v0.18.0
golang.org/x/sync v0.7.0
golang.org/x/text v0.16.0
golang.org/x/tools v0.23.0
)
require (
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 // indirect
gioui.org/shader v1.0.6 // indirect
github.com/benoitkugler/textlayout v0.1.1 // indirect
github.com/gioui/uax v0.2.1-0.20220325163150-e3d987515a12 // indirect
github.com/go-text/typesetting v0.0.0-20220411150340-35994bc27a7b // indirect
gioui.org/shader v1.0.8 // indirect
github.com/go-text/typesetting v0.2.1 // indirect
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect
github.com/gobwas/pool v0.2.0 // indirect
github.com/gobwas/ws v1.0.2 // indirect
github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08 // indirect
github.com/mailru/easyjson v0.7.0 // indirect
golang.org/x/exp v0.0.0-20210722180016-6781d3edade3 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 // indirect
golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37 // indirect
golang.org/x/mod v0.19.0 // indirect
golang.org/x/sys v0.22.0 // indirect
)
+26 -102
View File
@@ -1,120 +1,44 @@
eliasnaur.com/font v0.0.0-20220124212145-832bb8fc08c3 h1:djFprmHZgrSepsHAIRMp5UJn3PzsoTg9drI+BDmif5Q=
gioui.org v0.0.0-20220628163331-e21c665e70ae h1:s8Erm0/zVvi3Fbq0ijjPkRT04XxcGZWTxkxDwUBsxuQ=
gioui.org v0.0.0-20220628163331-e21c665e70ae/go.mod h1:WHoHbUjH91BJS2xkfps2AhKxji+9o3xwfsphGsCBfnM=
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d h1:ARo7NCVvN2NdhLlJE9xAbKweuI9L6UgfTbYb0YwPacY=
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d/go.mod h1:OYVuxibdk9OSLX8vAqydtRPP87PyTFcT9uH3MlEGBQA=
gioui.org v0.8.0 h1:QV5p5JvsmSmGiIXVYOKn6d9YDliTfjtLlVf5J+BZ9Pg=
gioui.org v0.8.0/go.mod h1:vEMmpxMOd/iwJhXvGVIzWEbxMWhnMQ9aByOGQdlQ8rc=
gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 h1:AGDDxsJE1RpcXTAxPG2B4jrwVUJGFDjINIPi1jtO6pc=
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
gioui.org/shader v1.0.6 h1:cvZmU+eODFR2545X+/8XucgZdTtEjR3QWW6W65b0q5Y=
gioui.org/shader v1.0.6/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA=
gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
github.com/akavel/rsrc v0.10.1 h1:hCCPImjmFKVNGpeLZyTDRHEFC283DzyTXTo0cO0Rq9o=
github.com/akavel/rsrc v0.10.1/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/benoitkugler/pstokenizer v1.0.0/go.mod h1:l1G2Voirz0q/jj0TQfabNxVsa8HZXh/VMxFSRALWTiE=
github.com/benoitkugler/textlayout v0.0.5/go.mod h1:puH4v13Uz7uIhIH0XMk5jgc8U3MXcn5r3VlV9K8n0D8=
github.com/benoitkugler/textlayout v0.1.1 h1:hizE/085xAeY8q7gwV00uHR2Q27KYB2g1HW+UacXl68=
github.com/benoitkugler/textlayout v0.1.1/go.mod h1:o+1hFV+JSHBC9qNLIuwVoLedERU7sBPgEFcuSgfvi/w=
github.com/benoitkugler/textlayout-testdata v0.1.1 h1:AvFxBxpfrQd8v55qH59mZOJOQjtD6K2SFe9/HvnIbJk=
github.com/chromedp/cdproto v0.0.0-20191114225735-6626966fbae4 h1:QD3KxSJ59L2lxG6MXBjNHxiQO2RmxTQ3XcK+wO44WOg=
github.com/chromedp/cdproto v0.0.0-20191114225735-6626966fbae4/go.mod h1:PfAWWKJqjlGFYJEidUM6aVIWPr0EpobeyVWEEmplX7g=
github.com/chromedp/chromedp v0.5.2 h1:W8xBXQuUnd2dZK0SN/lyVwsQM7KgW+kY5HGnntms194=
github.com/chromedp/chromedp v0.5.2/go.mod h1:rsTo/xRo23KZZwFmWk2Ui79rBaVRRATCjLzNQlOFSiA=
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gioui/uax v0.2.1-0.20220325163150-e3d987515a12 h1:1bjaB/5IIicfKpP4k0s30T2WEw//Kh00zULa8DQ0cxA=
github.com/gioui/uax v0.2.1-0.20220325163150-e3d987515a12/go.mod h1:kDhBRTA/i3H46PVdhqcw26TdGSIj42TOKNWKY+Kipnw=
github.com/go-text/typesetting v0.0.0-20220411150340-35994bc27a7b h1:WINlj3ANt+CVrO2B4NGDHRlPvEWZPxjhb7z+JKypwXI=
github.com/go-text/typesetting v0.0.0-20220411150340-35994bc27a7b/go.mod h1:ZNYu5saGoMOqtkVH5T8onTwhzenDUVszI+5WFHJRaxQ=
github.com/go-text/typesetting v0.2.1 h1:x0jMOGyO3d1qFAPI0j4GSsh7M0Q3Ypjzr4+CEVg82V8=
github.com/go-text/typesetting v0.2.1/go.mod h1:mTOxEwasOFpAMBjEQDhdWRckoLLeI/+qrQeBCTGEt6M=
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0=
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08 h1:V0an7KRw92wmJysvFvtqtKMAPmvS5O0jtB0nYo6t+gs=
github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08/go.mod h1:dFWs1zEqDjFtnBXsd1vPOZaLsESovai349994nHx3e0=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20210722180016-6781d3edade3 h1:IlrJD2AM5p8JhN/wVny9jt6gJ9hut2VALhSeZ3SYluk=
golang.org/x/exp v0.0.0-20210722180016-6781d3edade3/go.mod h1:DVyR6MI7P4kEQgvZJSj1fQGrWIi2RzIrfYWycwheUAc=
golang.org/x/image v0.0.0-20210504121937-7319ad40d33e/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37 h1:SOSg7+sueresE4IbmmGM60GmlIys+zNX63d6/J4CMtU=
golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37/go.mod h1:3F+MieQB7dRYLTmnncoFbb1crS5lfQoTfDgQy6K4N0o=
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
+22 -18
View File
@@ -8,7 +8,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
@@ -42,7 +41,7 @@ var exeSuffix string
type manifestData struct {
AppID string
Version int
Version Semver
MinSDK int
TargetSDK int
Permissions []string
@@ -240,7 +239,7 @@ func compileAndroid(tmpDir string, tools *androidTools, bi *buildInfo) (err erro
return err
})
}
appDir, err := runCmd(exec.Command("go", "list", "-f", "{{.Dir}}", "gioui.org/app/"))
appDir, err := runCmd(exec.Command("go", "list", "-tags", bi.tags, "-f", "{{.Dir}}", "gioui.org/app/"))
if err != nil {
return err
}
@@ -353,15 +352,18 @@ func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo, extraJars, pe
if err := os.MkdirAll(dexDir, 0755); err != nil {
return err
}
// https://developer.android.com/distribute/best-practices/develop/target-sdk
targetSDK := 31
if bi.minsdk > targetSDK {
targetSDK = bi.minsdk
}
minSDK := 16
if bi.minsdk > minSDK {
minSDK = bi.minsdk
}
// https://developer.android.com/distribute/best-practices/develop/target-sdk
targetSDK := 33
if bi.targetsdk > 0 {
targetSDK = bi.targetsdk
}
if minSDK > targetSDK {
targetSDK = minSDK
}
if len(classFiles) > 0 {
d8 := exec.Command(
filepath.Join(tools.buildtools, "d8"),
@@ -405,7 +407,7 @@ func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo, extraJars, pe
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(v26mipmapDir, `ic_launcher.xml`), []byte(`<?xml version="1.0" encoding="utf-8"?>
err = os.WriteFile(filepath.Join(v26mipmapDir, `ic_launcher.xml`), []byte(`<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_adaptive" />
<foreground android:drawable="@mipmap/ic_launcher_adaptive" />
@@ -415,11 +417,11 @@ func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo, extraJars, pe
}
iconSnip = `android:icon="@mipmap/ic_launcher"`
}
err = ioutil.WriteFile(filepath.Join(valDir, "themes.xml"), []byte(themes), 0660)
err = os.WriteFile(filepath.Join(valDir, "themes.xml"), []byte(themes), 0660)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(v21Dir, "themes.xml"), []byte(themesV21), 0660)
err = os.WriteFile(filepath.Join(v21Dir, "themes.xml"), []byte(themesV21), 0660)
if err != nil {
return err
}
@@ -436,7 +438,7 @@ func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo, extraJars, pe
// Link APK.
permissions, features := getPermissions(perms)
appName := strings.Title(bi.name)
appName := UppercaseName(bi.name)
manifestSrc := manifestData{
AppID: bi.appID,
Version: bi.version,
@@ -451,8 +453,8 @@ func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo, extraJars, pe
`<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="{{.AppID}}"
android:versionCode="{{.Version}}"
android:versionName="1.0.{{.Version}}">
android:versionCode="{{.Version.VersionCode}}"
android:versionName="{{.Version}}">
<uses-sdk android:minSdkVersion="{{.MinSDK}}" android:targetSdkVersion="{{.TargetSDK}}" />
{{range .Permissions}} <uses-permission android:name="{{.}}"/>
{{end}}{{range .Features}} <uses-feature android:{{.}} android:required="false"/>
@@ -475,7 +477,7 @@ func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo, extraJars, pe
return err
}
manifest := filepath.Join(tmpDir, "AndroidManifest.xml")
if err := ioutil.WriteFile(manifest, manifestBuffer.Bytes(), 0660); err != nil {
if err := os.WriteFile(manifest, manifestBuffer.Bytes(), 0660); err != nil {
return err
}
@@ -769,7 +771,9 @@ func findKeytool() (string, error) {
if javaHome == "" {
return exec.LookPath("keytool")
}
keytool := filepath.Join(javaHome, "jre", "bin", "keytool"+exeSuffix)
// bin, instead of "jre". "jre" was for older JVM it seems.
keytool := filepath.Join(javaHome, "bin", "keytool"+exeSuffix)
if _, err := os.Stat(keytool); err != nil {
return "", err
}
@@ -989,12 +993,12 @@ func (z *zipWriter) Close() error {
func (z *zipWriter) Create(name string) io.Writer {
if z.err != nil {
return ioutil.Discard
return io.Discard
}
w, err := z.w.Create(name)
if err != nil {
z.err = err
return ioutil.Discard
return io.Discard
}
return &errWriter{w: w, err: &z.err}
}
+78 -28
View File
@@ -9,22 +9,33 @@ import (
"path/filepath"
"runtime"
"strings"
"unicode"
"unicode/utf8"
)
type buildInfo struct {
appID string
archs []string
ldflags string
minsdk int
name string
pkgDir string
pkgPath string
iconPath string
tags string
target string
version int
key string
password string
appID string
archs []string
ldflags string
minsdk int
targetsdk int
name string
pkgDir string
pkgPath string
iconPath string
tags string
target string
version Semver
key string
password string
notaryAppleID string
notaryPassword string
notaryTeamID string
}
type Semver struct {
Major, Minor, Patch int
VersionCode uint32
}
func newBuildInfo(pkgPath string) (*buildInfo, error) {
@@ -37,24 +48,58 @@ func newBuildInfo(pkgPath string) (*buildInfo, error) {
if *iconPath != "" {
appIcon = *iconPath
}
appName := getPkgName(pkgMetadata)
if *name != "" {
appName = *name
}
ver, err := parseSemver(*version)
if err != nil {
return nil, err
}
bi := &buildInfo{
appID: appID,
archs: getArchs(),
ldflags: getLdFlags(appID),
minsdk: *minsdk,
name: getPkgName(pkgMetadata),
pkgDir: pkgMetadata.Dir,
pkgPath: pkgPath,
iconPath: appIcon,
tags: *extraTags,
target: *target,
version: *version,
key: *signKey,
password: *signPass,
appID: appID,
archs: getArchs(),
ldflags: getLdFlags(appID),
minsdk: *minsdk,
targetsdk: *targetsdk,
name: appName,
pkgDir: pkgMetadata.Dir,
pkgPath: pkgPath,
iconPath: appIcon,
tags: *extraTags,
target: *target,
version: ver,
key: *signKey,
password: *signPass,
notaryAppleID: *notaryID,
notaryPassword: *notaryPass,
notaryTeamID: *notaryTeamID,
}
return bi, nil
}
// UppercaseName returns a string with its first rune in uppercase.
func UppercaseName(name string) string {
ch, w := utf8.DecodeRuneInString(name)
return string(unicode.ToUpper(ch)) + name[w:]
}
func (s Semver) String() string {
return fmt.Sprintf("%d.%d.%d.%d", s.Major, s.Minor, s.Patch, s.VersionCode)
}
func parseSemver(v string) (Semver, error) {
var sv Semver
_, err := fmt.Sscanf(v, "%d.%d.%d.%d", &sv.Major, &sv.Minor, &sv.Patch, &sv.VersionCode)
if err != nil {
return Semver{}, fmt.Errorf("invalid semver: %q", v)
}
if sv.String() != v {
return Semver{}, fmt.Errorf("invalid semver: %q", v)
}
return sv, nil
}
func getArchs() []string {
if *archNames != "" {
return strings.Split(*archNames, ",")
@@ -73,6 +118,8 @@ func getArchs() []string {
goarch = runtime.GOARCH
}
return []string{goarch}
case "macos":
return []string{"arm64", "amd64"}
default:
// TODO: Add flag tests.
panic("The target value has already been validated, this will never execute.")
@@ -85,6 +132,9 @@ func getLdFlags(appID string) string {
ldflags = append(ldflags, strings.Split(extra, " ")...)
}
// Pass appID along, to be used for logging on platforms like Android.
ldflags = append(ldflags, fmt.Sprintf("-X gioui.org/app.ID=%s", appID))
// Support earlier Gio versions that had a separate app id recorded.
// TODO: delete this in the future.
ldflags = append(ldflags, fmt.Sprintf("-X gioui.org/app/internal/log.appID=%s", appID))
// Pass along all remaining arguments to the app.
if appArgs := flag.Args()[1:]; len(appArgs) > 0 {
@@ -102,11 +152,11 @@ type packageMetadata struct {
}
func getPkgMetadata(pkgPath string) (*packageMetadata, error) {
pkgImportPath, err := runCmd(exec.Command("go", "list", "-f", "{{.ImportPath}}", pkgPath))
pkgImportPath, err := runCmd(exec.Command("go", "list", "-tags", *extraTags, "-f", "{{.ImportPath}}", pkgPath))
if err != nil {
return nil, err
}
pkgDir, err := runCmd(exec.Command("go", "list", "-f", "{{.Dir}}", pkgPath))
pkgDir, err := runCmd(exec.Command("go", "list", "-tags", *extraTags, "-f", "{{.Dir}}", pkgPath))
if err != nil {
return nil, err
}
+2 -3
View File
@@ -10,7 +10,6 @@ import (
"image"
"image/color"
"io"
"io/ioutil"
"os"
"os/exec"
"runtime"
@@ -83,7 +82,7 @@ func TestEndToEnd(t *testing.T) {
}{
{"X11 using go import path", &X11TestDriver{}, testdataWithGoImportPkgPath, ""},
{"X11", &X11TestDriver{}, testdataWithRelativePkgPath, ""},
{"X11 with custom rendering", &X11TestDriver{}, customRenderTestdataWithRelativePkgPath, "openbsd"},
{"X11 with custom rendering", &X11TestDriver{}, customRenderTestdataWithRelativePkgPath, "openbsd,darwin,windows,netbsd"},
// Doesn't work on the builders.
//{"Wayland", &WaylandTestDriver{}, testdataWithRelativePkgPath},
{"JS", &JSTestDriver{}, testdataWithRelativePkgPath, ""},
@@ -316,7 +315,7 @@ func (d *driverBase) needPrograms(names ...string) {
func (d *driverBase) tempDir(name string) string {
d.Helper()
dir, err := ioutil.TempDir("", name)
dir, err := os.MkdirTemp("", name)
if err != nil {
d.Fatal(err)
}
+16 -2
View File
@@ -18,7 +18,8 @@ Compiled Java class files from jar files in the package directory are
included in Android builds.
The mandatory -target flag selects the target platform: ios or android for the
mobile platforms, tvos for Apple's tvOS, js for WebAssembly/WebGL.
mobile platforms, tvos for Apple's tvOS, js for WebAssembly/WebGL, macos for
MacOS and windows for Windows.
The -arch flag specifies a comma separated list of GOARCHs to include. The
default is all supported architectures.
@@ -58,12 +59,25 @@ use -mindk 10 to target Windows 10 and later, -minsdk 6 for Windows Vista and la
For iOS builds the -minsdk flag specify the minimum iOS version. For example,
use -mindk 15 to target iOS 15.0 and later.
For Android builds the -targetsdk flag specify the target SDK level. For example,
use -targetsdk 33 to target Android 13 (Tiramisu) and later.
The -work flag prints the path to the working directory and suppress
its deletion.
The -x flag will print all the external commands executed by the gogio tool.
The -signkey flag specifies the path of the keystore, used for signing Android apk/aab files.
The -signkey flag specifies the path of the keystore, used for signing Android apk/aab files
or specifies the name of key on Keychain to sign MacOS app.
The -signpass flag specifies the password of the keystore, ignored if -signkey is not provided.
The -notaryid flag specifies the Apple ID to use for notarization of MacOS app.
The -notarypass flag specifies the password of the Apple ID, ignored if -notaryid is not
provided. That must be an app-specific password, see https://support.apple.com/en-us/HT204397
for details. If not provided, the password will be prompted.
The -notaryteamid flag specifies the team ID to use for notarization of MacOS app, ignored if
-notaryid is not provided.
`
+19 -15
View File
@@ -20,8 +20,8 @@ import (
"gioui.org/app"
"gioui.org/gpu"
"gioui.org/io/event"
"gioui.org/io/pointer"
"gioui.org/io/system"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/op/clip"
@@ -98,7 +98,8 @@ type eglContext struct {
func main() {
go func() {
// Set CustomRenderer so we can provide our own rendering context.
w := app.NewWindow(app.CustomRenderer(true))
w := new(app.Window)
w.Option(app.CustomRenderer(true))
if err := loop(w); err != nil {
log.Fatal(err)
}
@@ -164,17 +165,17 @@ func loop(w *app.Window) error {
// eglMakeCurrent binds a context to an operating system thread. Prevent Go from switching thread.
runtime.LockOSThread()
for e := range w.Events() {
switch e := e.(type) {
for {
switch e := w.Event().(type) {
case app.ViewEvent:
ve = e
init = true
if size != (image.Point{}) {
recreateContext()
}
case system.DestroyEvent:
case app.DestroyEvent:
return e.Err
case system.FrameEvent:
case app.FrameEvent:
if init && size != e.Size {
size = e.Size
recreateContext()
@@ -183,7 +184,7 @@ func loop(w *app.Window) error {
break
}
// Build ops.
gtx := layout.NewContext(&ops, e)
gtx := app.NewContext(&ops, e)
// Clear background to white, even on embedded platforms such as webassembly.
paint.Fill(gtx.Ops, color.NRGBA{A: 0xff, R: 0xff, G: 0xff, B: 0xff})
@@ -205,7 +206,7 @@ func loop(w *app.Window) error {
)
}),
)
op.InvalidateOp{}.Add(gtx.Ops)
gtx.Execute(op.InvalidateCmd{})
log.Println("frame")
// Trigger window resize detection in ANGLE.
@@ -351,13 +352,16 @@ func (w *quarterWidget) Layout(gtx layout.Context) layout.Dimensions {
defer clip.Rect(image.Rectangle{
Max: image.Pt(gtx.Constraints.Max.X, gtx.Constraints.Max.Y),
}).Push(gtx.Ops).Pop()
pointer.InputOp{
Tag: w,
Types: pointer.Press,
}.Add(gtx.Ops)
for _, e := range gtx.Events(w) {
if e, ok := e.(pointer.Event); ok && e.Type == pointer.Press {
event.Op(gtx.Ops, w)
for {
e, ok := gtx.Event(pointer.Filter{
Target: w,
Kinds: pointer.Press,
})
if !ok {
break
}
if e, ok := e.(pointer.Event); ok && e.Kind == pointer.Press {
w.clicked = !w.clicked
// notify when we're done updating the frame.
notify = notifyInvalidate
+17 -12
View File
@@ -10,8 +10,8 @@ import (
"log"
"gioui.org/app"
"gioui.org/io/event"
"gioui.org/io/pointer"
"gioui.org/io/system"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/op/clip"
@@ -20,7 +20,7 @@ import (
func main() {
go func() {
w := app.NewWindow()
w := new(app.Window)
if err := loop(w); err != nil {
log.Fatal(err)
}
@@ -61,12 +61,12 @@ func loop(w *app.Window) error {
var ops op.Ops
for {
e := <-w.Events()
e := w.Event()
switch e := e.(type) {
case system.DestroyEvent:
case app.DestroyEvent:
return e.Err
case system.FrameEvent:
gtx := layout.NewContext(&ops, e)
case app.FrameEvent:
gtx := app.NewContext(&ops, e)
// Clear background to white, even on embedded platforms such as webassembly.
paint.Fill(gtx.Ops, color.NRGBA{A: 0xff, R: 0xff, G: 0xff, B: 0xff})
layout.Flex{Axis: layout.Vertical}.Layout(gtx,
@@ -126,13 +126,18 @@ func (w *quarterWidget) Layout(gtx layout.Context) layout.Dimensions {
defer clip.Rect(image.Rectangle{
Max: image.Pt(gtx.Constraints.Max.X, gtx.Constraints.Max.Y),
}).Push(gtx.Ops).Pop()
pointer.InputOp{
Tag: w,
Types: pointer.Press,
}.Add(gtx.Ops)
event.Op(gtx.Ops, w)
filter := pointer.Filter{
Target: w,
Kinds: pointer.Press,
}
for _, e := range gtx.Events(w) {
if e, ok := e.(pointer.Event); ok && e.Type == pointer.Press {
for {
e, ok := gtx.Event(filter)
if !ok {
break
}
if e, ok := e.(pointer.Event); ok && e.Kind == pointer.Press {
w.clicked = !w.clicked
// notify when we're done updating the frame.
notify = notifyInvalidate
+35 -78
View File
@@ -9,7 +9,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
@@ -22,6 +21,8 @@ import (
const (
minIOSVersion = 10
// Some Metal features require tvOS 11
minTVOSVersion = 11
// Metal is available from iOS 8 on devices, yet from version 13 on the
// simulator.
minSimulatorVersion = 13
@@ -33,7 +34,7 @@ func buildIOS(tmpDir, target string, bi *buildInfo) error {
case "archive":
framework := *destPath
if framework == "" {
framework = fmt.Sprintf("%s.framework", strings.Title(appName))
framework = fmt.Sprintf("%s.framework", UppercaseName(appName))
}
return archiveIOS(tmpDir, target, framework, bi)
case "exe":
@@ -57,10 +58,6 @@ func buildIOS(tmpDir, target string, bi *buildInfo) error {
bi.archs = append(bi.archs[:i], bi.archs[i+1:]...)
}
tmpFramework := filepath.Join(tmpDir, "Gio.framework")
if err := archiveIOS(tmpDir, target, tmpFramework, bi); err != nil {
return err
}
if !forDevice && !strings.HasSuffix(out, ".app") {
return fmt.Errorf("the specified output directory %q does not end in .app or .ipa", out)
}
@@ -142,7 +139,7 @@ func signIOS(bi *buildInfo, tmpDir, app string) error {
return err
}
entFile := filepath.Join(tmpDir, "entitlements.plist")
if err := ioutil.WriteFile(entFile, []byte(entitlements), 0660); err != nil {
if err := os.WriteFile(entFile, []byte(entitlements), 0660); err != nil {
return err
}
identity := sha1.Sum(certDER)
@@ -163,33 +160,7 @@ func exeIOS(tmpDir, target, app string, bi *buildInfo) error {
if err := os.Mkdir(app, 0755); err != nil {
return err
}
mainm := filepath.Join(tmpDir, "main.m")
const mainmSrc = `@import UIKit;
@import Gio;
@interface GioAppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
@implementation GioAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
GioViewController *controller = [[GioViewController alloc] initWithNibName:nil bundle:nil];
self.window.rootViewController = controller;
[self.window makeKeyAndVisible];
return YES;
}
@end
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([GioAppDelegate class]));
}
}`
if err := ioutil.WriteFile(mainm, []byte(mainmSrc), 0660); err != nil {
return err
}
appName := strings.Title(bi.name)
appName := UppercaseName(bi.name)
exe := filepath.Join(app, appName)
lipo := exec.Command("xcrun", "lipo", "-o", exe, "-create")
var builds errgroup.Group
@@ -198,17 +169,28 @@ int main(int argc, char * argv[]) {
if err != nil {
return err
}
cflags = append(cflags,
"-fobjc-arc",
)
cflagsLine := strings.Join(cflags, " ")
exeSlice := filepath.Join(tmpDir, "app-"+a)
lipo.Args = append(lipo.Args, exeSlice)
compile := exec.Command(clang, cflags...)
compile.Args = append(compile.Args,
"-Werror",
"-fmodules",
"-fobjc-arc",
"-x", "objective-c",
"-F", tmpDir,
compile := exec.Command(
"go",
"build",
"-ldflags=-s -w "+bi.ldflags,
"-o", exeSlice,
mainm,
"-tags", bi.tags,
bi.pkgPath,
)
compile.Env = append(
os.Environ(),
"GOOS=ios",
"GOARCH="+a,
"CGO_ENABLED=1",
"CC="+clang,
"CGO_CFLAGS="+cflagsLine,
"CGO_LDFLAGS=-lresolv "+cflagsLine,
)
builds.Go(func() error {
_, err := runCmd(compile)
@@ -223,7 +205,7 @@ int main(int argc, char * argv[]) {
}
infoPlist := buildInfoPlist(bi)
plistFile := filepath.Join(app, "Info.plist")
if err := ioutil.WriteFile(plistFile, []byte(infoPlist), 0660); err != nil {
if err := os.WriteFile(plistFile, []byte(infoPlist), 0660); err != nil {
return err
}
if _, err := os.Stat(bi.iconPath); err == nil {
@@ -288,7 +270,7 @@ func iosIcons(bi *buildInfo, tmpDir, appDir, icon string) (string, error) {
]
}`
contentFile := filepath.Join(appIcon, "Contents.json")
if err := ioutil.WriteFile(contentFile, []byte(contentJson), 0600); err != nil {
if err := os.WriteFile(contentFile, []byte(contentJson), 0600); err != nil {
return "", err
}
assetPlist := filepath.Join(tmpDir, "assets.plist")
@@ -310,7 +292,7 @@ func iosIcons(bi *buildInfo, tmpDir, appDir, icon string) (string, error) {
}
func buildInfoPlist(bi *buildInfo) string {
appName := strings.Title(bi.name)
appName := UppercaseName(bi.name)
platform := iosPlatformFor(bi.target)
var supportPlatform string
switch bi.target {
@@ -336,7 +318,7 @@ func buildInfoPlist(bi *buildInfo) string {
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.%d</string>
<string>%s</string>
<key>CFBundleVersion</key>
<string>%d</string>
<key>UILaunchStoryboardName</key>
@@ -377,7 +359,7 @@ func buildInfoPlist(bi *buildInfo) string {
<key>DTXcodeBuild</key>
<string>10G8</string>
</dict>
</plist>`, appName, bi.appID, appName, bi.version, bi.version, platform, minIOSVersion, supportPlatform, platform)
</plist>`, appName, bi.appID, appName, bi.version, bi.version.VersionCode, platform, minIOSVersion, supportPlatform, platform)
}
func iosPlatformFor(target string) string {
@@ -423,16 +405,6 @@ func archiveIOS(tmpDir, target, frameworkRoot string, bi *buildInfo) error {
lipo := exec.Command("xcrun", "lipo", "-o", exe, "-create")
var builds errgroup.Group
tags := bi.tags
goos := "ios"
supportsIOS, err := supportsGOOS("ios")
if err != nil {
return err
}
if !supportsIOS {
// Go 1.15 and earlier target iOS with GOOS=darwin, tags=ios.
goos = "darwin"
tags = "ios " + tags
}
for _, a := range bi.archs {
clang, cflags, err := iosCompilerFor(target, a, bi.minsdk)
if err != nil {
@@ -452,7 +424,7 @@ func archiveIOS(tmpDir, target, frameworkRoot string, bi *buildInfo) error {
cflagsLine := strings.Join(cflags, " ")
cmd.Env = append(
os.Environ(),
"GOOS="+goos,
"GOOS=ios",
"GOARCH="+a,
"CGO_ENABLED=1",
"CC="+clang,
@@ -470,7 +442,7 @@ func archiveIOS(tmpDir, target, frameworkRoot string, bi *buildInfo) error {
if _, err := runCmd(lipo); err != nil {
return err
}
appDir, err := runCmd(exec.Command("go", "list", "-f", "{{.Dir}}", "gioui.org/app/"))
appDir, err := runCmd(exec.Command("go", "list", "-tags", tags, "-f", "{{.Dir}}", "gioui.org/app/"))
if err != nil {
return err
}
@@ -485,25 +457,7 @@ func archiveIOS(tmpDir, target, frameworkRoot string, bi *buildInfo) error {
export *
}`, framework)
moduleFile := filepath.Join(frameworkDir, "Modules", "module.modulemap")
return ioutil.WriteFile(moduleFile, []byte(module), 0644)
}
func supportsGOOS(wantGoos string) (bool, error) {
geese, err := runCmd(exec.Command("go", "tool", "dist", "list"))
if err != nil {
return false, err
}
for _, pair := range strings.Split(geese, "\n") {
s := strings.SplitN(pair, "/", 2)
if len(s) != 2 {
return false, fmt.Errorf("go tool dist list: invalid GOOS/GOARCH pair: %s", pair)
}
goos := s[0]
if goos == wantGoos {
return true, nil
}
}
return false, nil
return os.WriteFile(moduleFile, []byte(module), 0644)
}
func iosCompilerFor(target, arch string, minsdk int) (string, []string, error) {
@@ -524,6 +478,9 @@ func iosCompilerFor(target, arch string, minsdk int) (string, []string, error) {
platformSDK += "os"
if minsdk == 0 {
minsdk = minIOSVersion
if target == "tvos" {
minsdk = minTVOSVersion
}
}
case "386", "amd64":
platformOS += "-simulator"
+3 -4
View File
@@ -6,7 +6,6 @@ import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
@@ -45,11 +44,11 @@ func buildJS(bi *buildInfo) error {
var faviconPath string
if _, err := os.Stat(bi.iconPath); err == nil {
// Copy icon to the output folder
icon, err := ioutil.ReadFile(bi.iconPath)
icon, err := os.ReadFile(bi.iconPath)
if err != nil {
return err
}
if err := ioutil.WriteFile(filepath.Join(out, filepath.Base(bi.iconPath)), icon, 0600); err != nil {
if err := os.WriteFile(filepath.Join(out, filepath.Base(bi.iconPath)), icon, 0600); err != nil {
return err
}
faviconPath = filepath.Base(bi.iconPath)
@@ -71,7 +70,7 @@ func buildJS(bi *buildInfo) error {
return err
}
if err := ioutil.WriteFile(filepath.Join(out, "index.html"), b.Bytes(), 0600); err != nil {
if err := os.WriteFile(filepath.Join(out, "index.html"), b.Bytes(), 0600); err != nil {
return err
}
+262
View File
@@ -0,0 +1,262 @@
package main
import (
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"text/template"
)
func buildMac(tmpDir string, bi *buildInfo) error {
builder := &macBuilder{TempDir: tmpDir}
builder.DestDir = *destPath
if builder.DestDir == "" {
builder.DestDir = bi.pkgPath
}
name := bi.name
if *destPath != "" {
if filepath.Ext(*destPath) != ".app" {
return fmt.Errorf("invalid output name %q, it must end with `.app`", *destPath)
}
name = filepath.Base(*destPath)
}
name = strings.TrimSuffix(name, ".app")
if bi.appID == "" {
return errors.New("app id is empty; use -appid to set it")
}
if err := builder.setIcon(bi.iconPath); err != nil {
return err
}
if err := builder.setInfo(bi, name); err != nil {
return fmt.Errorf("can't build the resources: %v", err)
}
for _, arch := range bi.archs {
tmpDest := filepath.Join(builder.TempDir, filepath.Base(builder.DestDir))
finalDest := builder.DestDir
if len(bi.archs) > 1 {
tmpDest = filepath.Join(builder.TempDir, name+"_"+arch+".app")
finalDest = filepath.Join(builder.DestDir, name+"_"+arch+".app")
}
if err := builder.buildProgram(bi, tmpDest, name, arch); err != nil {
return err
}
if bi.key != "" {
if err := builder.signProgram(bi, tmpDest, name, arch); err != nil {
return err
}
}
if err := dittozip(tmpDest, tmpDest+".zip"); err != nil {
return err
}
if bi.notaryAppleID != "" {
if err := builder.notarize(bi, tmpDest+".zip"); err != nil {
return err
}
}
if err := dittounzip(tmpDest+".zip", finalDest); err != nil {
return err
}
}
return nil
}
type macBuilder struct {
TempDir string
DestDir string
Icons []byte
Manifest []byte
Entitlements []byte
}
func (b *macBuilder) setIcon(path string) (err error) {
if _, err := os.Stat(path); err != nil {
return nil
}
out := filepath.Join(b.TempDir, "iconset.iconset")
if err := os.MkdirAll(out, 0777); err != nil {
return err
}
err = buildIcons(out, path, []iconVariant{
{path: "icon_512x512@2x.png", size: 1024},
{path: "icon_512x512.png", size: 512},
{path: "icon_256x256@2x.png", size: 512},
{path: "icon_256x256.png", size: 256},
{path: "icon_128x128@2x.png", size: 256},
{path: "icon_128x128.png", size: 128},
{path: "icon_64x64@2x.png", size: 128},
{path: "icon_64x64.png", size: 64},
{path: "icon_32x32@2x.png", size: 64},
{path: "icon_32x32.png", size: 32},
{path: "icon_16x16@2x.png", size: 32},
{path: "icon_16x16.png", size: 16},
})
if err != nil {
return err
}
cmd := exec.Command("iconutil",
"-c", "icns", out,
"-o", filepath.Join(b.TempDir, "icon.icns"))
if _, err := runCmd(cmd); err != nil {
return err
}
b.Icons, err = os.ReadFile(filepath.Join(b.TempDir, "icon.icns"))
return err
}
func (b *macBuilder) setInfo(buildInfo *buildInfo, name string) error {
t, err := template.New("manifest").Parse(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>{{.Name}}</string>
<key>CFBundleIconFile</key>
<string>icon.icns</string>
<key>CFBundleIdentifier</key>
<string>{{.Bundle}}</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>CFBundlePackageType</key>
<string>APPL</string>
</dict>
</plist>`)
if err != nil {
return err
}
var manifest bufferCoff
if err := t.Execute(&manifest, struct {
Name, Bundle string
}{
Name: name,
Bundle: buildInfo.appID,
}); err != nil {
return err
}
b.Manifest = manifest.Bytes()
b.Entitlements = []byte(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
</dict>
</plist>`)
return nil
}
func (b *macBuilder) buildProgram(buildInfo *buildInfo, binDest string, name string, arch string) error {
for _, path := range []string{"/Contents/MacOS", "/Contents/Resources"} {
if err := os.MkdirAll(filepath.Join(binDest, path), 0755); err != nil {
return err
}
}
if len(b.Icons) > 0 {
if err := os.WriteFile(filepath.Join(binDest, "/Contents/Resources/icon.icns"), b.Icons, 0755); err != nil {
return err
}
}
if err := os.WriteFile(filepath.Join(binDest, "/Contents/Info.plist"), b.Manifest, 0755); err != nil {
return err
}
cmd := exec.Command(
"go",
"build",
"-ldflags="+buildInfo.ldflags,
"-tags="+buildInfo.tags,
"-o", filepath.Join(binDest, "/Contents/MacOS/"+name),
buildInfo.pkgPath,
)
cmd.Env = append(
os.Environ(),
"GOOS=darwin",
"GOARCH="+arch,
"CGO_ENABLED=1", // Required to cross-compile between AMD/ARM
)
_, err := runCmd(cmd)
return err
}
func (b *macBuilder) signProgram(buildInfo *buildInfo, binDest string, name string, arch string) error {
options := filepath.Join(b.TempDir, "ent.ent")
if err := os.WriteFile(options, b.Entitlements, 0777); err != nil {
return err
}
xattr := exec.Command("xattr", "-rc", binDest)
if _, err := runCmd(xattr); err != nil {
return err
}
cmd := exec.Command(
"codesign",
"--deep",
"--force",
"--options", "runtime",
"--entitlements", options,
"--sign", buildInfo.key,
binDest,
)
_, err := runCmd(cmd)
return err
}
func (b *macBuilder) notarize(buildInfo *buildInfo, binDest string) error {
cmd := exec.Command(
"xcrun",
"notarytool",
"submit",
binDest,
"--apple-id", buildInfo.notaryAppleID,
"--team-id", buildInfo.notaryTeamID,
"--wait",
)
if buildInfo.notaryPassword != "" {
cmd.Args = append(cmd.Args, "--password", buildInfo.notaryPassword)
}
_, err := runCmd(cmd)
return err
}
func dittozip(input, output string) error {
cmd := exec.Command("ditto", "-c", "-k", "-X", "--rsrc", input, output)
_, err := runCmd(cmd)
return err
}
func dittounzip(input, output string) error {
cmd := exec.Command("ditto", "-x", "-k", "-X", "--rsrc", input, output)
_, err := runCmd(cmd)
return err
}
+10 -7
View File
@@ -11,7 +11,6 @@ import (
"image/color"
"image/png"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
@@ -25,10 +24,12 @@ var (
target = flag.String("target", "", "specify target (ios, tvos, android, js).\n")
archNames = flag.String("arch", "", "specify architecture(s) to include (arm, arm64, amd64).")
minsdk = flag.Int("minsdk", 0, "specify the minimum supported operating system level")
targetsdk = flag.Int("targetsdk", 0, "specify the target supported operating system level for Android")
buildMode = flag.String("buildmode", "exe", "specify buildmode (archive, exe)")
destPath = flag.String("o", "", "output file or directory.\nFor -target ios or tvos, use the .app suffix to target simulators.")
appID = flag.String("appid", "", "app identifier (for -buildmode=exe)")
version = flag.Int("version", 1, "app version (for -buildmode=exe)")
name = flag.String("name", "", "app name (for -buildmode=exe)")
version = flag.String("version", "1.0.0.1", "semver app version (for -buildmode=exe) on the form major.minor.patch.versioncode")
printCommands = flag.Bool("x", false, "print the commands")
keepWorkdir = flag.Bool("work", false, "print the name of the temporary work directory and do not delete it when exiting.")
linkMode = flag.String("linkmode", "", "set the -linkmode flag of the go tool")
@@ -37,6 +38,9 @@ var (
iconPath = flag.String("icon", "", "specify an icon for iOS and Android")
signKey = flag.String("signkey", "", "specify the path of the keystore to be used to sign Android apk files.")
signPass = flag.String("signpass", "", "specify the password to decrypt the signkey.")
notaryID = flag.String("notaryid", "", "specify the apple id to use for notarization.")
notaryPass = flag.String("notarypass", "", "specify app-specific password of the Apple ID to be used for notarization.")
notaryTeamID = flag.String("notaryteamid", "", "specify the team id to use for notarization.")
)
func main() {
@@ -65,14 +69,11 @@ func flagValidate() error {
if pkgPathArg == "" {
return errors.New("specify a package")
}
if len(flag.Args()) > 1 {
return fmt.Errorf("build arguments must be specified before the package (%q)", pkgPathArg)
}
if *target == "" {
return errors.New("please specify -target")
}
switch *target {
case "ios", "tvos", "android", "js", "windows":
case "ios", "tvos", "android", "js", "windows", "macos":
default:
return fmt.Errorf("invalid -target %s", *target)
}
@@ -85,7 +86,7 @@ func flagValidate() error {
}
func build(bi *buildInfo) error {
tmpDir, err := ioutil.TempDir("", "gogio-")
tmpDir, err := os.MkdirTemp("", "gogio-")
if err != nil {
return err
}
@@ -103,6 +104,8 @@ func build(bi *buildInfo) error {
return buildAndroid(tmpDir, bi)
case "windows":
return buildWindows(tmpDir, bi)
case "macos":
return buildMac(tmpDir, bi)
default:
panic("unreachable")
}
+3
View File
@@ -19,6 +19,9 @@ var AndroidPermissions = map[string][]string{
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE",
},
"wakelock": {
"android.permission.WAKE_LOCK",
},
}
var AndroidFeatures = map[string][]string{
+3 -9
View File
@@ -7,12 +7,10 @@ import (
"fmt"
"image/png"
"io"
"math"
"os"
"os/exec"
"path/filepath"
"reflect"
"strconv"
"strings"
"text/template"
@@ -40,10 +38,6 @@ func buildWindows(tmpDir string, bi *buildInfo) error {
if sdk > 10 {
return fmt.Errorf("invalid minsdk (%d) it's higher than Windows 10", sdk)
}
version := strconv.Itoa(bi.version)
if bi.version > math.MaxUint16 {
return fmt.Errorf("version (%d) is larger than the maximum (%d)", bi.version, math.MaxUint16)
}
for _, arch := range bi.archs {
builder.Coff = coff.NewRSRC()
@@ -54,7 +48,7 @@ func buildWindows(tmpDir string, bi *buildInfo) error {
}
if err := builder.embedManifest(windowsManifest{
Version: "1.0.0." + version,
Version: bi.version.String(),
WindowsVersion: sdk,
Name: name,
}); err != nil {
@@ -62,8 +56,8 @@ func buildWindows(tmpDir string, bi *buildInfo) error {
}
if err := builder.embedInfo(windowsResources{
Version: [2]uint32{uint32(1) << 16, uint32(bi.version)},
VersionHuman: "1.0.0." + version,
Version: [2]uint32{uint32(bi.version.Major), uint32(bi.version.Minor)<<16 | uint32(bi.version.Patch)},
VersionHuman: bi.version.String(),
Name: name,
Language: 0x0400, // Process Default Language: https://docs.microsoft.com/en-us/previous-versions/ms957130(v=msdn.10)
}); err != nil {
+582
View File
@@ -0,0 +1,582 @@
// SPDX-License-Identifier: Unlicense OR MIT
// Command svg2gio converts SVG files to Gio functions. Only a limited subset of
// SVG files are supported.
package main
import (
"bytes"
"encoding/xml"
"errors"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"strconv"
"strings"
"unicode"
"go/format"
"gioui.org/f32"
)
var (
pkg = flag.String("pkg", "", "Go package")
output = flag.String("o", "svg.go", "Output Go file")
)
func main() {
flag.Parse()
if *pkg == "" {
fmt.Fprintf(os.Stderr, "specify a package name (-pkg)\n")
os.Exit(1)
}
args := flag.Args()
if err := convertAll(args); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(2)
}
}
type Points []float32
func (p *Points) UnmarshalText(text []byte) error {
for {
text = bytes.TrimLeft(text, "\t\n")
if len(text) == 0 {
break
}
var num []byte
end := bytes.IndexAny(text, " ,")
if end != -1 {
num = text[:end]
text = text[end+1:]
} else {
num = text
text = nil
}
f, err := strconv.ParseFloat(string(num), 32)
if err != nil {
return err
}
*p = append(*p, float32(f))
}
return nil
}
type Transform f32.Affine2D
func (t *Transform) UnmarshalText(text []byte) error {
switch {
case bytes.HasPrefix(text, []byte("matrix(")) && bytes.HasSuffix(text, []byte(")")):
trans := text[7 : len(text)-1]
var p Points
if err := p.UnmarshalText(trans); err != nil {
return err
}
if len(p) != 6 {
return fmt.Errorf("malformed transform matrix: %q", text)
}
*t = Transform(f32.NewAffine2D(p[0], p[2], p[4], p[1], p[3], p[5]))
return nil
default:
return fmt.Errorf("unsupported transform: %q", text)
}
}
type Fill struct {
Transform Transform `xml:"transform,attr"`
Fill Color `xml:"fill,attr"`
Stroke Color `xml:"stroke,attr"`
StrokeLinejoin string `xml:"stroke-linejoin,attr"`
StrokeLinecap string `xml:"stroke-linecap,attr"`
StrokeWidth float32 `xml:"stroke-width,attr"`
}
type Color struct {
Set bool
Value int
}
func (c *Color) UnmarshalText(text []byte) error {
if string(text) == "none" {
*c = Color{}
return nil
}
if !bytes.HasPrefix(text, []byte("#")) {
return fmt.Errorf("invalid color: %q", text)
}
text = text[1:]
i, err := strconv.ParseInt(string(text), 16, 32)
// Implied alpha.
if len(text) == 6 {
i |= 0xff000000
}
*c = Color{
Set: true,
Value: int(i),
}
return err
}
func convertAll(files []string) error {
w := new(bytes.Buffer)
fmt.Fprintf(w, "// Code generated by gioui.org/cmd/svg2gio; DO NOT EDIT.\n\n")
fmt.Fprintf(w, "package %s\n\n", *pkg)
fmt.Fprintf(w, "import \"image/color\"\n")
fmt.Fprintf(w, "import \"math\"\n")
fmt.Fprintf(w, "import \"gioui.org/op\"\n")
fmt.Fprintf(w, "import \"gioui.org/op/clip\"\n")
fmt.Fprintf(w, "import \"gioui.org/op/paint\"\n")
fmt.Fprintf(w, "import \"gioui.org/f32\"\n\n")
fmt.Fprintf(w, "var ops op.Ops\n\n")
fmt.Fprintf(w, funcs)
for _, filename := range files {
if err := convert(w, filename); err != nil {
return err
}
}
src, err := format.Source(w.Bytes())
if err != nil {
return err
}
return os.WriteFile(*output, src, 0o660)
}
func convert(w io.Writer, filename string) error {
base := filepath.Base(filename)
ext := filepath.Ext(base)
name := "Image_" + base[:len(base)-len(ext)]
fmt.Fprintf(w, "var %s struct {\n", name)
fmt.Fprintf(w, "ViewBox struct { Min, Max f32.Point }\n")
fmt.Fprintf(w, "Call op.CallOp\n\n")
fmt.Fprintf(w, "}\n")
fmt.Fprintf(w, "func init() {\n")
defer fmt.Fprintf(w, "}\n")
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close()
d := xml.NewDecoder(f)
if err := parse(w, d, name); err != nil {
line, col := d.InputPos()
return fmt.Errorf("%s:%d:%d: %w", filename, line, col, err)
}
return nil
}
func parse(w io.Writer, d *xml.Decoder, name string) error {
for {
tok, err := d.Token()
if err != nil {
if err == io.EOF {
return errors.New("unexpected end of file")
}
return err
}
switch tok := tok.(type) {
case xml.StartElement:
if n := tok.Name.Local; n != "svg" {
return fmt.Errorf("invalid SVG root: <%s>", n)
}
if n := tok.Name.Space; n != "http://www.w3.org/2000/svg" {
return fmt.Errorf("unsupported SVG namespace: %s", n)
}
fmt.Fprintf(w, "m := op.Record(&ops)\n")
defer fmt.Fprintf(w, "%s.Call = m.Stop()\n", name)
for _, a := range tok.Attr {
if a.Name.Local == "viewBox" {
var p Points
if err := p.UnmarshalText([]byte(a.Value)); err != nil {
return fmt.Errorf("invalid viewBox attribute: %s", a.Value)
}
if len(p) != 4 {
return fmt.Errorf("invalid viewBox attribute: %s", a.Value)
}
fmt.Fprintf(w, "%s.ViewBox.Min = %s\n", name, point(f32.Pt(p[0], p[1])))
fmt.Fprintf(w, "%s.ViewBox.Max = %s\n", name, point(f32.Pt(p[2], p[3])))
}
}
return parseSVG(w, d)
}
}
}
func point(p f32.Point) string {
return fmt.Sprintf("f32.Pt(%g, %g)", p.X, p.Y)
}
type Poly struct {
XMLName xml.Name
Points Points `xml:"points,attr"`
Fill
}
func (p *Poly) Path(w io.Writer) error {
if len(p.Points) <= 1 {
return nil
}
pen := f32.Pt(p.Points[0], p.Points[1])
fmt.Fprintf(w, "p.MoveTo(%s)\n", point(pen))
last := pen
for i := 2; i < len(p.Points); i += 2 {
last = f32.Pt(p.Points[i], p.Points[i+1])
fmt.Fprintf(w, "p.LineTo(%s)\n", point(last))
}
if p.XMLName.Local == "polygon" && last != pen {
fmt.Fprintf(w, "p.LineTo(%s)\n", point(pen))
}
return nil
}
type Path struct {
D string `xml:"d,attr"`
Fill
}
func (p *Path) Path(w io.Writer) error {
return printPathCommands(w, p.D)
}
type Line struct {
X1 float32 `xml:"x1,attr"`
Y1 float32 `xml:"y1,attr"`
X2 float32 `xml:"x2,attr"`
Y2 float32 `xml:"y2,attr"`
Fill
}
func (l *Line) Path(w io.Writer) error {
fmt.Fprintf(w, "p.MoveTo(%s)\n", point(f32.Pt(l.X1, l.Y1)))
fmt.Fprintf(w, "p.LineTo(%s)\n", point(f32.Pt(l.X2, l.Y2)))
return nil
}
type Ellipse struct {
Cx float32 `xml:"cx,attr"`
Cy float32 `xml:"cy,attr"`
Rx float32 `xml:"rx,attr"`
Ry float32 `xml:"ry,attr"`
Fill
}
func (e *Ellipse) Path(w io.Writer) error {
c := f32.Pt(e.Cx, e.Cy)
r := f32.Pt(e.Rx, e.Ry)
fmt.Fprintf(w, "ellipse(&p, %s, %s)\n", point(c), point(r))
return nil
}
type Rect struct {
X float32 `xml:"x,attr"`
Y float32 `xml:"y,attr"`
Width float32 `xml:"width,attr"`
Height float32 `xml:"height,attr"`
Fill
}
func (r *Rect) Path(w io.Writer) error {
o := f32.Pt(r.X, r.Y)
sz := f32.Pt(r.Width, r.Height)
fmt.Fprintf(w, "rect(&p, %s, %s)\n", point(o), point(sz))
return nil
}
type Circle struct {
Cx float32 `xml:"cx,attr"`
Cy float32 `xml:"cy,attr"`
R float32 `xml:"r,attr"`
Fill
}
func (c *Circle) Path(w io.Writer) error {
center := f32.Pt(c.Cx, c.Cy)
r := f32.Pt(c.R, c.R)
fmt.Fprintf(w, "ellipse(&p, %s, %s)\n", point(center), point(r))
return nil
}
func parseSVG(w io.Writer, d *xml.Decoder) error {
for {
tok, err := d.Token()
if err != nil {
if err == io.EOF {
return errors.New("unexpected end of <svg> element")
}
return err
}
var start xml.StartElement
switch tok := tok.(type) {
case xml.EndElement:
return nil
case xml.StartElement:
start = tok
default:
continue
}
var elem interface {
Path(w io.Writer) error
}
var fill *Fill
switch n := start.Name.Local; n {
case "g":
// Flatten groups.
if err := parseSVG(w, d); err != nil {
return err
}
continue
case "title":
d.Skip()
continue
case "polygon", "polyline":
p := new(Poly)
elem = p
fill = &p.Fill
case "path":
p := new(Path)
elem = p
fill = &p.Fill
case "line":
l := new(Line)
elem = l
fill = &l.Fill
case "ellipse":
e := new(Ellipse)
elem = e
fill = &e.Fill
case "rect":
r := new(Rect)
elem = r
fill = &r.Fill
case "circle":
c := new(Circle)
elem = c
fill = &c.Fill
default:
return fmt.Errorf("unsupported tag: <%s>", n)
}
if err := d.DecodeElement(elem, &start); err != nil {
return err
}
if !fill.Fill.Set && !fill.Stroke.Set {
continue
}
fmt.Fprintf(w, "{\n")
trans := f32.Affine2D(fill.Transform)
if trans != (f32.Affine2D{}) {
sx, hx, ox, sy, hy, oy := trans.Elems()
fmt.Fprintf(w, "t := op.Affine(f32.NewAffine2D(%g, %g, %g, %g, %g, %g)).Push(&ops)\n", sx, hx, ox, sy, hy, oy)
}
fmt.Fprintf(w, "var p clip.Path\n")
fmt.Fprintf(w, "p.Begin(&ops)\n")
if err := elem.Path(w); err != nil {
return err
}
fmt.Fprintf(w, "spec := p.End()\n")
if fill.Fill.Set {
fmt.Fprintf(w, "paint.FillShape(&ops, argb(%#.8x), clip.Outline{Path: spec}.Op())\n", fill.Fill.Value)
}
if fill.Stroke.Set {
fmt.Fprintf(w, "paint.FillShape(&ops, argb(%#.8x), clip.Stroke{Width: %g, Path: spec}.Op())\n", fill.Stroke.Value, fill.StrokeWidth)
}
if trans != (f32.Affine2D{}) {
fmt.Fprintf(w, "t.Pop()\n")
}
fmt.Fprintf(w, "}\n")
}
}
func printPathCommands(w io.Writer, cmds string) error {
moveTo := func(p f32.Point) {
fmt.Fprintf(w, "p.MoveTo(%s)\n", point(p))
}
lineTo := func(p f32.Point) {
fmt.Fprintf(w, "p.LineTo(%s)\n", point(p))
}
cubeTo := func(p0, p1, p2 f32.Point) {
fmt.Fprintf(w, "p.CubeTo(%s, %s, %s)\n", point(p0), point(p1), point(p2))
}
cmds = strings.TrimSpace(cmds)
var pen f32.Point
initPoint := pen
ctrl2 := pen
for {
cmds = strings.TrimLeft(cmds, " ,\t\n")
if len(cmds) == 0 {
break
}
orig := cmds
op := rune(cmds[0])
cmds = cmds[1:]
switch op {
case 'M', 'm', 'V', 'v', 'L', 'l', 'H', 'h', 'C', 'c', 'S', 's':
case 'Z', 'z':
if pen != initPoint {
lineTo(initPoint)
pen = initPoint
}
ctrl2 = initPoint
continue
default:
return fmt.Errorf("unknown <path> command %s in %q", string(op), orig)
}
var coords []float64
for {
cmds = strings.TrimLeft(cmds, " ,\t\n")
if len(cmds) == 0 {
break
}
n, x, ok := parseFloat(cmds)
if !ok {
break
}
cmds = cmds[n:]
coords = append(coords, x)
}
rel := unicode.IsLower(op)
newPen := pen
switch unicode.ToLower(op) {
case 'h':
for _, x := range coords {
p := f32.Pt(float32(x), pen.Y)
if rel {
p.X += pen.X
}
lineTo(p)
newPen = p
}
pen = newPen
ctrl2 = newPen
continue
case 'v':
for _, y := range coords {
p := f32.Pt(pen.X, float32(y))
if rel {
p.Y += pen.Y
}
lineTo(p)
newPen = p
}
pen = newPen
ctrl2 = newPen
continue
}
if len(coords)%2 != 0 {
return fmt.Errorf("odd number of coordinates in <path> data: %q", orig)
}
var off f32.Point
if rel {
// Relative command.
off = pen
} else {
off = f32.Pt(0, 0)
}
var points []f32.Point
for i := 0; i < len(coords); i += 2 {
p := f32.Pt(float32(coords[i]), float32(coords[i+1]))
p = p.Add(off)
points = append(points, p)
}
newCtrl2 := ctrl2
switch op := unicode.ToLower(op); op {
case 'm', 'l':
sop := moveTo
if op == 'l' {
sop = lineTo
}
for _, p := range points {
sop(p)
newPen = p
}
if op == 'm' {
initPoint = newPen
}
case 'c':
for i := 0; i < len(points); i += 3 {
p1, p2, p3 := points[i], points[i+1], points[i+2]
cubeTo(p1, p2, p3)
newPen = p3
newCtrl2 = p2
}
case 's':
for i := 0; i < len(points); i += 2 {
p2, p3 := points[i], points[i+1]
// Compute p1 by reflecting p2 on to the line that contains pen and p2.
p1 := pen.Mul(2).Sub(ctrl2)
cubeTo(p1, p2, p3)
newPen = p3
newCtrl2 = p2
}
}
pen = newPen
ctrl2 = newCtrl2
}
return nil
}
func parseFloat(s string) (int, float64, bool) {
n := 0
if len(s) > 0 && s[0] == '-' {
n++
}
for ; n < len(s); n++ {
if !(unicode.IsDigit(rune(s[n])) || s[n] == '.') {
break
}
}
f, err := strconv.ParseFloat(s[:n], 64)
return n, f, err == nil
}
const funcs = `
func argb(c uint32) color.NRGBA {
return color.NRGBA{A: uint8(c >> 24), R: uint8(c >> 16), G: uint8(c >> 8), B: uint8(c)}
}
func rect(p *clip.Path, origin, size f32.Point) {
p.MoveTo(origin)
p.LineTo(origin.Add(f32.Pt(size.X, 0)))
p.LineTo(origin.Add(size))
p.LineTo(origin.Add(f32.Pt(0, size.Y)))
p.Close()
}
func ellipse(p *clip.Path, center, radius f32.Point) {
r := radius.X
// We'll model the ellipse as a circle scaled in the Y
// direction.
scale := radius.Y / r
// https://pomax.github.io/bezierinfo/#circles_cubic.
const q = 4 * (math.Sqrt2 - 1) / 3
curve := r * q
top := f32.Point{X: center.X, Y: center.Y - r*scale}
p.MoveTo(top)
p.CubeTo(
f32.Point{X: center.X + curve, Y: center.Y - r*scale},
f32.Point{X: center.X + r, Y: center.Y - curve*scale},
f32.Point{X: center.X + r, Y: center.Y},
)
p.CubeTo(
f32.Point{X: center.X + r, Y: center.Y + curve*scale},
f32.Point{X: center.X + curve, Y: center.Y + r*scale},
f32.Point{X: center.X, Y: center.Y + r*scale},
)
p.CubeTo(
f32.Point{X: center.X - curve, Y: center.Y + r*scale},
f32.Point{X: center.X - r, Y: center.Y + curve*scale},
f32.Point{X: center.X - r, Y: center.Y},
)
p.CubeTo(
f32.Point{X: center.X - r, Y: center.Y - curve*scale},
f32.Point{X: center.X - curve, Y: center.Y - r*scale},
top,
)
}
`