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
|
||||
|
||||
require (
|
||||
gioui.org v0.0.0-20220328154813-a3f147541fd0
|
||||
gioui.org v0.0.0-20220628163331-e21c665e70ae
|
||||
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.6
|
||||
golang.org/x/text v0.3.7
|
||||
golang.org/x/tools v0.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 // 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/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/pool v0.2.0 // indirect
|
||||
github.com/gobwas/ws v1.0.2 // indirect
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
gioui.org v0.0.0-20220328154813-a3f147541fd0 h1:n4FUiCT6P4a2wF6hwX4a5R8TpjAhu/d+3nhwZW16MAI=
|
||||
gioui.org v0.0.0-20220328154813-a3f147541fd0/go.mod h1:b8vBukexG6eYuXZa14asjLAWJ+JjbZ/ophEnS2FjYUg=
|
||||
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=
|
||||
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=
|
||||
@@ -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/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.10 h1:uIaQgH4pBFw1LQ0tPkfjgxo94WYcckzzQaB41L2X84w=
|
||||
github.com/benoitkugler/textlayout v0.0.10/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=
|
||||
@@ -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/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-20220112121102-58fe93c84506 h1:1TPz/Gn/MsXwJ6bEtI9wdkPcQYr2X3V9I+wz4wPYUdY=
|
||||
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 h1:WINlj3ANt+CVrO2B4NGDHRlPvEWZPxjhb7z+JKypwXI=
|
||||
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/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
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-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 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
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=
|
||||
@@ -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/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 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
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=
|
||||
|
||||
+17
-10
@@ -13,6 +13,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -69,27 +70,33 @@ func TestEndToEnd(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const (
|
||||
testdataWithGoImportPkgPath = "gioui.org/cmd/gogio/testdata"
|
||||
testdataWithRelativePkgPath = "testdata/testdata.go"
|
||||
testdataWithGoImportPkgPath = "gioui.org/cmd/gogio/internal/normal"
|
||||
testdataWithRelativePkgPath = "internal/normal/testdata.go"
|
||||
customRenderTestdataWithRelativePkgPath = "internal/custom/testdata.go"
|
||||
)
|
||||
// Keep this list local, to not reuse TestDriver objects.
|
||||
subtests := []struct {
|
||||
name string
|
||||
driver TestDriver
|
||||
pkgPath string
|
||||
name string
|
||||
driver TestDriver
|
||||
pkgPath string
|
||||
skipGeese string
|
||||
}{
|
||||
{"X11 using go import path", &X11TestDriver{}, testdataWithGoImportPkgPath},
|
||||
{"X11", &X11TestDriver{}, testdataWithRelativePkgPath},
|
||||
{"X11 using go import path", &X11TestDriver{}, testdataWithGoImportPkgPath, ""},
|
||||
{"X11", &X11TestDriver{}, testdataWithRelativePkgPath, ""},
|
||||
{"X11 with custom rendering", &X11TestDriver{}, customRenderTestdataWithRelativePkgPath, "openbsd"},
|
||||
// Doesn't work on the builders.
|
||||
//{"Wayland", &WaylandTestDriver{}, testdataWithRelativePkgPath},
|
||||
{"JS", &JSTestDriver{}, testdataWithRelativePkgPath},
|
||||
{"Android", &AndroidTestDriver{}, testdataWithRelativePkgPath},
|
||||
{"Windows", &WineTestDriver{}, testdataWithRelativePkgPath},
|
||||
{"JS", &JSTestDriver{}, testdataWithRelativePkgPath, ""},
|
||||
{"Android", &AndroidTestDriver{}, testdataWithRelativePkgPath, ""},
|
||||
{"Windows", &WineTestDriver{}, testdataWithRelativePkgPath, ""},
|
||||
}
|
||||
|
||||
for _, subtest := range subtests {
|
||||
t.Run(subtest.name, func(t *testing.T) {
|
||||
subtest := subtest // copy the changing loop variable
|
||||
if strings.Contains(subtest.skipGeese, runtime.GOOS) {
|
||||
t.Skipf("not supported on %s", runtime.GOOS)
|
||||
}
|
||||
t.Parallel()
|
||||
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