forked from joejulian/gio-cmd
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4113870ba2 | |||
| 333b1df54a |
@@ -3,22 +3,22 @@ module gioui.org/cmd
|
|||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
gioui.org v0.0.0-20220328154813-a3f147541fd0
|
gioui.org v0.0.0-20220628163331-e21c665e70ae
|
||||||
github.com/akavel/rsrc v0.10.1
|
github.com/akavel/rsrc v0.10.1
|
||||||
github.com/chromedp/cdproto v0.0.0-20191114225735-6626966fbae4
|
github.com/chromedp/cdproto v0.0.0-20191114225735-6626966fbae4
|
||||||
github.com/chromedp/chromedp v0.5.2
|
github.com/chromedp/chromedp v0.5.2
|
||||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
|
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
|
||||||
golang.org/x/text v0.3.6
|
golang.org/x/text v0.3.7
|
||||||
golang.org/x/tools v0.1.0
|
golang.org/x/tools v0.1.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 // indirect
|
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 // indirect
|
||||||
gioui.org/shader v1.0.6 // indirect
|
gioui.org/shader v1.0.6 // indirect
|
||||||
github.com/benoitkugler/textlayout v0.0.10 // indirect
|
github.com/benoitkugler/textlayout v0.1.1 // indirect
|
||||||
github.com/gioui/uax v0.2.1-0.20220325163150-e3d987515a12 // indirect
|
github.com/gioui/uax v0.2.1-0.20220325163150-e3d987515a12 // indirect
|
||||||
github.com/go-text/typesetting v0.0.0-20220112121102-58fe93c84506 // indirect
|
github.com/go-text/typesetting v0.0.0-20220411150340-35994bc27a7b // indirect
|
||||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect
|
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect
|
||||||
github.com/gobwas/pool v0.2.0 // indirect
|
github.com/gobwas/pool v0.2.0 // indirect
|
||||||
github.com/gobwas/ws v1.0.2 // indirect
|
github.com/gobwas/ws v1.0.2 // indirect
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
gioui.org v0.0.0-20220328154813-a3f147541fd0 h1:n4FUiCT6P4a2wF6hwX4a5R8TpjAhu/d+3nhwZW16MAI=
|
eliasnaur.com/font v0.0.0-20220124212145-832bb8fc08c3 h1:djFprmHZgrSepsHAIRMp5UJn3PzsoTg9drI+BDmif5Q=
|
||||||
gioui.org v0.0.0-20220328154813-a3f147541fd0/go.mod h1:b8vBukexG6eYuXZa14asjLAWJ+JjbZ/ophEnS2FjYUg=
|
gioui.org v0.0.0-20220628163331-e21c665e70ae h1:s8Erm0/zVvi3Fbq0ijjPkRT04XxcGZWTxkxDwUBsxuQ=
|
||||||
|
gioui.org v0.0.0-20220628163331-e21c665e70ae/go.mod h1:WHoHbUjH91BJS2xkfps2AhKxji+9o3xwfsphGsCBfnM=
|
||||||
gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
|
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 h1:AGDDxsJE1RpcXTAxPG2B4jrwVUJGFDjINIPi1jtO6pc=
|
||||||
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
|
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
|
||||||
@@ -9,8 +10,9 @@ 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/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/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.0.5/go.mod h1:puH4v13Uz7uIhIH0XMk5jgc8U3MXcn5r3VlV9K8n0D8=
|
||||||
github.com/benoitkugler/textlayout v0.0.10 h1:uIaQgH4pBFw1LQ0tPkfjgxo94WYcckzzQaB41L2X84w=
|
github.com/benoitkugler/textlayout v0.1.1 h1:hizE/085xAeY8q7gwV00uHR2Q27KYB2g1HW+UacXl68=
|
||||||
github.com/benoitkugler/textlayout v0.0.10/go.mod h1:puH4v13Uz7uIhIH0XMk5jgc8U3MXcn5r3VlV9K8n0D8=
|
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 h1:QD3KxSJ59L2lxG6MXBjNHxiQO2RmxTQ3XcK+wO44WOg=
|
||||||
github.com/chromedp/cdproto v0.0.0-20191114225735-6626966fbae4/go.mod h1:PfAWWKJqjlGFYJEidUM6aVIWPr0EpobeyVWEEmplX7g=
|
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 h1:W8xBXQuUnd2dZK0SN/lyVwsQM7KgW+kY5HGnntms194=
|
||||||
@@ -20,8 +22,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
|||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
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 h1:1bjaB/5IIicfKpP4k0s30T2WEw//Kh00zULa8DQ0cxA=
|
||||||
github.com/gioui/uax v0.2.1-0.20220325163150-e3d987515a12/go.mod h1:kDhBRTA/i3H46PVdhqcw26TdGSIj42TOKNWKY+Kipnw=
|
github.com/gioui/uax v0.2.1-0.20220325163150-e3d987515a12/go.mod h1:kDhBRTA/i3H46PVdhqcw26TdGSIj42TOKNWKY+Kipnw=
|
||||||
github.com/go-text/typesetting v0.0.0-20220112121102-58fe93c84506 h1:1TPz/Gn/MsXwJ6bEtI9wdkPcQYr2X3V9I+wz4wPYUdY=
|
github.com/go-text/typesetting v0.0.0-20220411150340-35994bc27a7b h1:WINlj3ANt+CVrO2B4NGDHRlPvEWZPxjhb7z+JKypwXI=
|
||||||
github.com/go-text/typesetting v0.0.0-20220112121102-58fe93c84506/go.mod h1:R0mlTNeyszZ/tKQhbZA7SRGjx+OHsmNzgN2jTV7yZcs=
|
github.com/go-text/typesetting v0.0.0-20220411150340-35994bc27a7b/go.mod h1:ZNYu5saGoMOqtkVH5T8onTwhzenDUVszI+5WFHJRaxQ=
|
||||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
|
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/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 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
|
||||||
@@ -60,7 +62,6 @@ golang.org/x/image v0.0.0-20210504121937-7319ad40d33e/go.mod h1:FeLwcggjj3mMvU+o
|
|||||||
golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
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 h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
|
||||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
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 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
@@ -93,8 +94,9 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
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.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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
|
||||||
golang.org/x/text v0.3.6/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-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-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.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
|||||||
+17
-10
@@ -13,6 +13,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -69,27 +70,33 @@ func TestEndToEnd(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
const (
|
const (
|
||||||
testdataWithGoImportPkgPath = "gioui.org/cmd/gogio/testdata"
|
testdataWithGoImportPkgPath = "gioui.org/cmd/gogio/internal/normal"
|
||||||
testdataWithRelativePkgPath = "testdata/testdata.go"
|
testdataWithRelativePkgPath = "internal/normal/testdata.go"
|
||||||
|
customRenderTestdataWithRelativePkgPath = "internal/custom/testdata.go"
|
||||||
)
|
)
|
||||||
// Keep this list local, to not reuse TestDriver objects.
|
// Keep this list local, to not reuse TestDriver objects.
|
||||||
subtests := []struct {
|
subtests := []struct {
|
||||||
name string
|
name string
|
||||||
driver TestDriver
|
driver TestDriver
|
||||||
pkgPath string
|
pkgPath string
|
||||||
|
skipGeese string
|
||||||
}{
|
}{
|
||||||
{"X11 using go import path", &X11TestDriver{}, testdataWithGoImportPkgPath},
|
{"X11 using go import path", &X11TestDriver{}, testdataWithGoImportPkgPath, ""},
|
||||||
{"X11", &X11TestDriver{}, testdataWithRelativePkgPath},
|
{"X11", &X11TestDriver{}, testdataWithRelativePkgPath, ""},
|
||||||
|
{"X11 with custom rendering", &X11TestDriver{}, customRenderTestdataWithRelativePkgPath, "openbsd"},
|
||||||
// Doesn't work on the builders.
|
// Doesn't work on the builders.
|
||||||
//{"Wayland", &WaylandTestDriver{}, testdataWithRelativePkgPath},
|
//{"Wayland", &WaylandTestDriver{}, testdataWithRelativePkgPath},
|
||||||
{"JS", &JSTestDriver{}, testdataWithRelativePkgPath},
|
{"JS", &JSTestDriver{}, testdataWithRelativePkgPath, ""},
|
||||||
{"Android", &AndroidTestDriver{}, testdataWithRelativePkgPath},
|
{"Android", &AndroidTestDriver{}, testdataWithRelativePkgPath, ""},
|
||||||
{"Windows", &WineTestDriver{}, testdataWithRelativePkgPath},
|
{"Windows", &WineTestDriver{}, testdataWithRelativePkgPath, ""},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, subtest := range subtests {
|
for _, subtest := range subtests {
|
||||||
t.Run(subtest.name, func(t *testing.T) {
|
t.Run(subtest.name, func(t *testing.T) {
|
||||||
subtest := subtest // copy the changing loop variable
|
subtest := subtest // copy the changing loop variable
|
||||||
|
if strings.Contains(subtest.skipGeese, runtime.GOOS) {
|
||||||
|
t.Skipf("not supported on %s", runtime.GOOS)
|
||||||
|
}
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
runEndToEndTest(t, subtest.driver, subtest.pkgPath)
|
runEndToEndTest(t, subtest.driver, subtest.pkgPath)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,367 @@
|
|||||||
|
// SPDX-License-Identifier: Unlicense OR MIT
|
||||||
|
|
||||||
|
//go:build linux
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
// This program demonstrates the use of a custom OpenGL ES context with
|
||||||
|
// app.Window.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"gioui.org/app"
|
||||||
|
"gioui.org/gpu"
|
||||||
|
"gioui.org/io/pointer"
|
||||||
|
"gioui.org/io/system"
|
||||||
|
"gioui.org/layout"
|
||||||
|
"gioui.org/op"
|
||||||
|
"gioui.org/op/clip"
|
||||||
|
"gioui.org/op/paint"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo linux pkg-config: egl wayland-egl
|
||||||
|
#cgo freebsd openbsd CFLAGS: -I/usr/local/include
|
||||||
|
#cgo openbsd CFLAGS: -I/usr/X11R6/include
|
||||||
|
#cgo freebsd LDFLAGS: -L/usr/local/lib
|
||||||
|
#cgo openbsd LDFLAGS: -L/usr/X11R6/lib
|
||||||
|
#cgo freebsd openbsd LDFLAGS: -lwayland-egl
|
||||||
|
#cgo CFLAGS: -DEGL_NO_X11
|
||||||
|
#cgo LDFLAGS: -lEGL -lGLESv2
|
||||||
|
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <wayland-client.h>
|
||||||
|
#include <wayland-egl.h>
|
||||||
|
#include <GLES3/gl3.h>
|
||||||
|
#define EGL_EGLEXT_PROTOTYPES
|
||||||
|
#include <EGL/eglext.h>
|
||||||
|
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func getDisplay(ve app.ViewEvent) C.EGLDisplay {
|
||||||
|
switch ve := ve.(type) {
|
||||||
|
case app.X11ViewEvent:
|
||||||
|
return C.eglGetDisplay(C.EGLNativeDisplayType(ve.Display))
|
||||||
|
case app.WaylandViewEvent:
|
||||||
|
return C.eglGetDisplay(C.EGLNativeDisplayType(ve.Display))
|
||||||
|
}
|
||||||
|
panic("no display available")
|
||||||
|
}
|
||||||
|
|
||||||
|
func nativeViewFor(e app.ViewEvent, size image.Point) (C.EGLNativeWindowType, func()) {
|
||||||
|
switch e := e.(type) {
|
||||||
|
case app.X11ViewEvent:
|
||||||
|
return C.EGLNativeWindowType(uintptr(e.Window)), func() {}
|
||||||
|
case app.WaylandViewEvent:
|
||||||
|
eglWin := C.wl_egl_window_create((*C.struct_wl_surface)(e.Surface), C.int(size.X), C.int(size.Y))
|
||||||
|
return C.EGLNativeWindowType(uintptr(unsafe.Pointer(eglWin))), func() {
|
||||||
|
C.wl_egl_window_destroy(eglWin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("no native view available")
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
C = layout.Context
|
||||||
|
D = layout.Dimensions
|
||||||
|
)
|
||||||
|
|
||||||
|
type notifyFrame int
|
||||||
|
|
||||||
|
const (
|
||||||
|
notifyNone notifyFrame = iota
|
||||||
|
notifyInvalidate
|
||||||
|
notifyPrint
|
||||||
|
)
|
||||||
|
|
||||||
|
// notify keeps track of whether we want to print to stdout to notify the user
|
||||||
|
// when a frame is ready. Initially we want to notify about the first frame.
|
||||||
|
var notify = notifyInvalidate
|
||||||
|
|
||||||
|
type eglContext struct {
|
||||||
|
disp C.EGLDisplay
|
||||||
|
ctx C.EGLContext
|
||||||
|
surf C.EGLSurface
|
||||||
|
cleanup func()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
go func() {
|
||||||
|
// Set CustomRenderer so we can provide our own rendering context.
|
||||||
|
w := app.NewWindow(app.CustomRenderer(true))
|
||||||
|
if err := loop(w); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
app.Main()
|
||||||
|
}
|
||||||
|
|
||||||
|
func loop(w *app.Window) error {
|
||||||
|
var ops op.Ops
|
||||||
|
var (
|
||||||
|
ctx *eglContext
|
||||||
|
gioCtx gpu.GPU
|
||||||
|
ve app.ViewEvent
|
||||||
|
init bool
|
||||||
|
size image.Point
|
||||||
|
)
|
||||||
|
|
||||||
|
recreateContext := func() {
|
||||||
|
w.Run(func() {
|
||||||
|
if gioCtx != nil {
|
||||||
|
gioCtx.Release()
|
||||||
|
gioCtx = nil
|
||||||
|
}
|
||||||
|
if ctx != nil {
|
||||||
|
C.eglMakeCurrent(ctx.disp, nil, nil, nil)
|
||||||
|
ctx.Release()
|
||||||
|
ctx = nil
|
||||||
|
}
|
||||||
|
c, err := createContext(ve, size)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx = c
|
||||||
|
})
|
||||||
|
if ok := C.eglMakeCurrent(ctx.disp, ctx.surf, ctx.surf, ctx.ctx); ok != C.EGL_TRUE {
|
||||||
|
err := fmt.Errorf("eglMakeCurrent failed (%#x)", C.eglGetError())
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
glGetString := func(e C.GLenum) string {
|
||||||
|
return C.GoString((*C.char)(unsafe.Pointer(C.glGetString(e))))
|
||||||
|
}
|
||||||
|
fmt.Printf("GL_VERSION: %s\nGL_RENDERER: %s\n", glGetString(C.GL_VERSION), glGetString(C.GL_RENDERER))
|
||||||
|
var err error
|
||||||
|
gioCtx, err = gpu.New(gpu.OpenGL{ES: true, Shared: true})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
topLeft := quarterWidget{
|
||||||
|
color: color.NRGBA{R: 0xde, G: 0xad, B: 0xbe, A: 0xff},
|
||||||
|
}
|
||||||
|
topRight := quarterWidget{
|
||||||
|
color: color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff},
|
||||||
|
}
|
||||||
|
botLeft := quarterWidget{
|
||||||
|
color: color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff},
|
||||||
|
}
|
||||||
|
botRight := quarterWidget{
|
||||||
|
color: color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0x80},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
case app.ViewEvent:
|
||||||
|
ve = e
|
||||||
|
init = true
|
||||||
|
if size != (image.Point{}) {
|
||||||
|
recreateContext()
|
||||||
|
}
|
||||||
|
case system.DestroyEvent:
|
||||||
|
return e.Err
|
||||||
|
case system.FrameEvent:
|
||||||
|
if init && size != e.Size {
|
||||||
|
size = e.Size
|
||||||
|
recreateContext()
|
||||||
|
}
|
||||||
|
if gioCtx == nil || !init {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Build ops.
|
||||||
|
gtx := layout.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,
|
||||||
|
layout.Flexed(1, func(gtx C) D {
|
||||||
|
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||||
|
// r1c1
|
||||||
|
layout.Flexed(1, func(gtx C) D { return topLeft.Layout(gtx) }),
|
||||||
|
// r1c2
|
||||||
|
layout.Flexed(1, func(gtx C) D { return topRight.Layout(gtx) }),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
layout.Flexed(1, func(gtx C) D {
|
||||||
|
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||||
|
// r2c1
|
||||||
|
layout.Flexed(1, func(gtx C) D { return botLeft.Layout(gtx) }),
|
||||||
|
// r2c2
|
||||||
|
layout.Flexed(1, func(gtx C) D { return botRight.Layout(gtx) }),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
op.InvalidateOp{}.Add(gtx.Ops)
|
||||||
|
log.Println("frame")
|
||||||
|
|
||||||
|
// Trigger window resize detection in ANGLE.
|
||||||
|
C.eglWaitClient()
|
||||||
|
// Draw custom OpenGL content.
|
||||||
|
drawGL()
|
||||||
|
|
||||||
|
// Render drawing ops.
|
||||||
|
if err := gioCtx.Frame(gtx.Ops, gpu.OpenGLRenderTarget{}, e.Size); err != nil {
|
||||||
|
log.Fatal(fmt.Errorf("render failed: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process non-drawing ops.
|
||||||
|
e.Frame(gtx.Ops)
|
||||||
|
switch notify {
|
||||||
|
case notifyInvalidate:
|
||||||
|
notify = notifyPrint
|
||||||
|
w.Invalidate()
|
||||||
|
case notifyPrint:
|
||||||
|
notify = notifyNone
|
||||||
|
fmt.Println("gio frame ready")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok := C.eglSwapBuffers(ctx.disp, ctx.surf); ok != C.EGL_TRUE {
|
||||||
|
log.Fatal(fmt.Errorf("swap failed: %v", C.eglGetError()))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func drawGL() {
|
||||||
|
C.glClearColor(0, 0, 0, 1)
|
||||||
|
C.glClear(C.GL_COLOR_BUFFER_BIT | C.GL_DEPTH_BUFFER_BIT)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createContext(ve app.ViewEvent, size image.Point) (*eglContext, error) {
|
||||||
|
view, cleanup := nativeViewFor(ve, size)
|
||||||
|
var nilv C.EGLNativeWindowType
|
||||||
|
if view == nilv {
|
||||||
|
return nil, fmt.Errorf("failed creating native view")
|
||||||
|
}
|
||||||
|
disp := getDisplay(ve)
|
||||||
|
if disp == 0 {
|
||||||
|
return nil, fmt.Errorf("eglGetPlatformDisplay failed: 0x%x", C.eglGetError())
|
||||||
|
}
|
||||||
|
var major, minor C.EGLint
|
||||||
|
if ok := C.eglInitialize(disp, &major, &minor); ok != C.EGL_TRUE {
|
||||||
|
return nil, fmt.Errorf("eglInitialize failed: 0x%x", C.eglGetError())
|
||||||
|
}
|
||||||
|
exts := strings.Split(C.GoString(C.eglQueryString(disp, C.EGL_EXTENSIONS)), " ")
|
||||||
|
srgb := hasExtension(exts, "EGL_KHR_gl_colorspace")
|
||||||
|
attribs := []C.EGLint{
|
||||||
|
C.EGL_RENDERABLE_TYPE, C.EGL_OPENGL_ES2_BIT,
|
||||||
|
C.EGL_SURFACE_TYPE, C.EGL_WINDOW_BIT,
|
||||||
|
C.EGL_BLUE_SIZE, 8,
|
||||||
|
C.EGL_GREEN_SIZE, 8,
|
||||||
|
C.EGL_RED_SIZE, 8,
|
||||||
|
C.EGL_CONFIG_CAVEAT, C.EGL_NONE,
|
||||||
|
}
|
||||||
|
if srgb {
|
||||||
|
// Some drivers need alpha for sRGB framebuffers to work.
|
||||||
|
attribs = append(attribs, C.EGL_ALPHA_SIZE, 8)
|
||||||
|
}
|
||||||
|
attribs = append(attribs, C.EGL_NONE)
|
||||||
|
var (
|
||||||
|
cfg C.EGLConfig
|
||||||
|
numCfgs C.EGLint
|
||||||
|
)
|
||||||
|
if ok := C.eglChooseConfig(disp, &attribs[0], &cfg, 1, &numCfgs); ok != C.EGL_TRUE {
|
||||||
|
return nil, fmt.Errorf("eglChooseConfig failed: 0x%x", C.eglGetError())
|
||||||
|
}
|
||||||
|
if numCfgs == 0 {
|
||||||
|
supportsNoCfg := hasExtension(exts, "EGL_KHR_no_config_context")
|
||||||
|
if !supportsNoCfg {
|
||||||
|
return nil, errors.New("eglChooseConfig returned no configs")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctxAttribs := []C.EGLint{
|
||||||
|
C.EGL_CONTEXT_CLIENT_VERSION, 3,
|
||||||
|
C.EGL_NONE,
|
||||||
|
}
|
||||||
|
ctx := C.eglCreateContext(disp, cfg, nil, &ctxAttribs[0])
|
||||||
|
if ctx == nil {
|
||||||
|
return nil, fmt.Errorf("eglCreateContext failed: 0x%x", C.eglGetError())
|
||||||
|
}
|
||||||
|
var surfAttribs []C.EGLint
|
||||||
|
if srgb {
|
||||||
|
surfAttribs = append(surfAttribs, C.EGL_GL_COLORSPACE, C.EGL_GL_COLORSPACE_SRGB)
|
||||||
|
}
|
||||||
|
surfAttribs = append(surfAttribs, C.EGL_NONE)
|
||||||
|
surf := C.eglCreateWindowSurface(disp, cfg, view, &surfAttribs[0])
|
||||||
|
if surf == nil {
|
||||||
|
return nil, fmt.Errorf("eglCreateWindowSurface failed (0x%x)", C.eglGetError())
|
||||||
|
}
|
||||||
|
return &eglContext{disp: disp, ctx: ctx, surf: surf, cleanup: cleanup}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *eglContext) Release() {
|
||||||
|
if c.ctx != nil {
|
||||||
|
C.eglDestroyContext(c.disp, c.ctx)
|
||||||
|
}
|
||||||
|
if c.surf != nil {
|
||||||
|
C.eglDestroySurface(c.disp, c.surf)
|
||||||
|
}
|
||||||
|
if c.cleanup != nil {
|
||||||
|
c.cleanup()
|
||||||
|
}
|
||||||
|
*c = eglContext{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasExtension(exts []string, ext string) bool {
|
||||||
|
for _, e := range exts {
|
||||||
|
if ext == e {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// quarterWidget paints a quarter of the screen with one color. When clicked, it
|
||||||
|
// turns red, going back to its normal color when clicked again.
|
||||||
|
type quarterWidget struct {
|
||||||
|
color color.NRGBA
|
||||||
|
|
||||||
|
clicked bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var red = color.NRGBA{R: 0xff, G: 0x00, B: 0x00, A: 0xff}
|
||||||
|
|
||||||
|
func (w *quarterWidget) Layout(gtx layout.Context) layout.Dimensions {
|
||||||
|
var color color.NRGBA
|
||||||
|
if w.clicked {
|
||||||
|
color = red
|
||||||
|
} else {
|
||||||
|
color = w.color
|
||||||
|
}
|
||||||
|
|
||||||
|
r := image.Rectangle{Max: gtx.Constraints.Max}
|
||||||
|
paint.FillShape(gtx.Ops, color, clip.Rect(r).Op())
|
||||||
|
|
||||||
|
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 {
|
||||||
|
w.clicked = !w.clicked
|
||||||
|
// notify when we're done updating the frame.
|
||||||
|
notify = notifyInvalidate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return layout.Dimensions{Size: gtx.Constraints.Max}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user