diff --git a/cmd/fyfoto/browser.go b/cmd/fyfoto/browser.go index 6529b90..ddee0a1 100644 --- a/cmd/fyfoto/browser.go +++ b/cmd/fyfoto/browser.go @@ -51,7 +51,7 @@ func populateLocal(ff *FyFoto, dir fyne.URI) { func populateSpace(ff *FyFoto) { // Get BC Node - node, err := ff.spaceFyne.GetNode(&ff.spaceClient.BCClient) + node, err := ff.spaceFyne.Node(ff.spaceClient) if err != nil { ff.spaceFyne.ShowError(err) return @@ -59,7 +59,7 @@ func populateSpace(ff *FyFoto) { populateSpaceWithNode(ff, node) } -func populateSpaceWithNode(ff *FyFoto, node *bcgo.Node) { +func populateSpaceWithNode(ff *FyFoto, node bcgo.Node) { // TODO Should this show a Progress Bar? /* TODO this API was removed in Fyne v2.0.0 @@ -140,7 +140,7 @@ func createBrowser(ff *FyFoto) { ff.spaceToolbar = widget.NewToolbar( widget.NewToolbarAction(theme.ContentAddIcon(), func() { go func() { - node, err := ff.spaceFyne.GetNode(&ff.spaceClient.BCClient) + node, err := ff.spaceFyne.Node(ff.spaceClient) if err != nil { ff.spaceFyne.ShowError(err) return @@ -156,18 +156,22 @@ func createBrowser(ff *FyFoto) { name := reader.URI().Name() // Show progress dialog - progress := dialog.NewProgress("Uploading", "Uploading "+name, ff.spaceFyne.Window) + progress := dialog.NewProgress("Uploading", "Uploading "+name, ff.spaceFyne.Window()) progress.Show() - defer progress.Hide() listener := &bcui.ProgressMiningListener{Func: progress.SetValue} reference, err := ff.spaceClient.Add(node, listener, name, reader.URI().MimeType(), reader) + + // Hide progress dialog + progress.Hide() + if err != nil { ff.spaceFyne.ShowError(err) + return } fmt.Println("Uploaded:", reference) go populateSpaceWithNode(ff, node) - }, ff.spaceFyne.Window) + }, ff.spaceFyne.Window()) d.SetFilter(storage.NewMimeTypeFileFilter([]string{"image/*"})) d.Show() }() @@ -183,7 +187,7 @@ func createBrowser(ff *FyFoto) { go ff.spaceFyne.ShowStorage(ff.spaceClient) }), widget.NewToolbarAction(theme.NewThemedResource(bcuidata.AccountIcon), func() { - go ff.spaceFyne.ShowAccount(&ff.spaceClient.BCClient) + go ff.spaceFyne.ShowAccount(ff.spaceClient) }), widget.NewToolbarAction(theme.HelpIcon(), func() { go ff.spaceFyne.ShowHelp(ff.spaceClient) @@ -194,7 +198,7 @@ func createBrowser(ff *FyFoto) { ) // Create list of thumbnails ff.spaceImages = ui.NewSpaceThumbnailTable(ff.spaceClient, func(id string, timestamp uint64, meta *spacego.Meta) { - node, err := ff.spaceFyne.GetNode(&ff.spaceClient.BCClient) + node, err := ff.spaceFyne.Node(ff.spaceClient) if err != nil { ff.spaceFyne.ShowError(err) return @@ -208,7 +212,7 @@ func createBrowser(ff *FyFoto) { file := filepath.Join(c, id) if _, err := os.Stat(file); os.IsNotExist(err) { - progress := dialog.NewProgressInfinite("Downloading", "Downloading "+meta.Name, ff.spaceFyne.Window) + progress := dialog.NewProgressInfinite("Downloading", "Downloading "+meta.Name, ff.spaceFyne.Window()) progress.Show() defer progress.Hide() diff --git a/cmd/fyfoto/main.go b/cmd/fyfoto/main.go index fa9b61d..7550e50 100644 --- a/cmd/fyfoto/main.go +++ b/cmd/fyfoto/main.go @@ -29,8 +29,8 @@ type FyFoto struct { localDirs *widget.Tree localImages *ui.LocalThumbnailTable - spaceClient *spaceclientgo.SpaceClient - spaceFyne *spacefynego.SpaceFyne + spaceClient spaceclientgo.SpaceClient + spaceFyne spacefynego.SpaceFyne spaceToolbar *widget.Toolbar spaceImages *ui.SpaceThumbnailTable @@ -57,27 +57,24 @@ func main() { flag.Parse() ff := &FyFoto{ - app: app.New(), + app: app.NewWithID("us.smhouston.fyfoto"), spaceClient: spaceclientgo.NewSpaceClient(), } ff.rootDir = storage.NewFileURI(*dirPtr) ff.window = ff.app.NewWindow("FyFoto") ff.spaceFyne = spacefynego.NewSpaceFyne(ff.app, ff.window, ff.spaceClient) - onSignedIn := ff.spaceFyne.OnSignedIn - ff.spaceFyne.OnSignedIn = func(node *bcgo.Node) { - if onSignedIn != nil { - onSignedIn(node) + ff.spaceFyne.AddOnSignedIn(func(bcgo.Account) { + node, err := ff.spaceFyne.Node(ff.spaceClient) + if err != nil { + log.Println(err) + return } go populateSpaceWithNode(ff, node) - } - onSignedOut := ff.spaceFyne.OnSignedOut - ff.spaceFyne.OnSignedOut = func() { - if onSignedOut != nil { - onSignedOut() - } + }) + ff.spaceFyne.AddOnSignedOut(func() { ff.spaceImages.Clear() ff.bInfo.SetText("") - } + }) createBrowser(ff) createViewer(ff) diff --git a/go.mod b/go.mod index 02622b8..3a1b923 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,11 @@ module github.com/okratitan/fyfoto go 1.12 require ( - aletheiaware.com/bcfynego v1.1.7 - aletheiaware.com/bcgo v1.1.4 - aletheiaware.com/spaceclientgo v1.1.5 - aletheiaware.com/spacefynego v1.1.4 - aletheiaware.com/spacego v1.1.4 - fyne.io/fyne/v2 v2.0.0 - golang.org/x/image v0.0.0-20201208152932-35266b937fa6 + aletheiaware.com/bcfynego v1.2.3 + aletheiaware.com/bcgo v1.2.3 + aletheiaware.com/spaceclientgo v1.2.4 + aletheiaware.com/spacefynego v1.2.4 + aletheiaware.com/spacego v1.2.4 + fyne.io/fyne/v2 v2.0.2 + golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb ) diff --git a/go.sum b/go.sum index e08db0d..86eae4b 100644 --- a/go.sum +++ b/go.sum @@ -1,28 +1,26 @@ -aletheiaware.com/aliasgo v1.1.3 h1:RnJhpWcbH7KWWWgIvUCVS+++mzpjYNk/dQm4o1G0lX8= -aletheiaware.com/aliasgo v1.1.3/go.mod h1:JY9/j4q6ZniHb0vKO7CJJ3M03eTVhczoIIhJBZ6Sa3w= -aletheiaware.com/bcclientgo v1.1.4 h1:mSdMxH3gNDYHOwfJTwVeQwxzJsZ5Trh8Wf5K1SG4IKM= -aletheiaware.com/bcclientgo v1.1.4/go.mod h1:Ra5xSJ6fPdlcEQR4bL9wVY6PiFmlfgHl8Z0U5k3GP8Y= -aletheiaware.com/bcfynego v1.1.7 h1:HV0GxLPumBg/HM95QWGsbMlVlKU5W81Qa80nOBK69x4= -aletheiaware.com/bcfynego v1.1.7/go.mod h1:T+Eb2fCbwpSTumyzf2WTG+kkqE6lEofSqnyRV0SKsIE= -aletheiaware.com/bcgo v1.1.4 h1:HuAk12UeOvtIXlc7WN2XIj9tV+jNA5uCi+D8Z0V2twU= -aletheiaware.com/bcgo v1.1.4/go.mod h1:GXvFFZ8JrATGrvuKA0J3ucf9+91eC94ggphNVpg3XUM= -aletheiaware.com/cryptogo v1.1.1 h1:XrzGXcTgYQbuL3tQv/idVzAIblb2k+o77iigiQiXTUQ= -aletheiaware.com/cryptogo v1.1.1/go.mod h1:sT8jDe5zWSIswZDAilLwfX2N6l4WOFQBm+4lYxx1Ae0= -aletheiaware.com/financego v1.1.3 h1:np43b+Vi2jK+PcjuZm97PJmtzIckhLVAHNFU5DzsKwI= -aletheiaware.com/financego v1.1.3/go.mod h1:Ht3zPGQyenlkxLXMQcKww6ctjt2bZcyLDdLz+/Koml0= -aletheiaware.com/spaceclientgo v1.1.5 h1:hR9z48oYpa88gU0ewgnZyPZLuSrjbwideABHKwK+t6Q= -aletheiaware.com/spaceclientgo v1.1.5/go.mod h1:9UhWgzhaDr2HGyoSuNSefa6bukH+BQDC8veDkZo5XQw= -aletheiaware.com/spacefynego v1.1.4 h1:jSNTJI763o0oqd/BB93eKAAnBba64fQO1lZEJTs8Tr4= -aletheiaware.com/spacefynego v1.1.4/go.mod h1:htqfmzacljRuX1C6FLgoBxRCMggFVW3Hwbne+MUVMU0= -aletheiaware.com/spacego v1.1.4 h1:xhC2zG40ZAZnEVjC9UcViAHIaJEN3kXHt/iym06z6bA= -aletheiaware.com/spacego v1.1.4/go.mod h1:4tu4NMQBJaio1lNlTqKzmvGOee+EAu7crT11D0LJeCA= -aletheiaware.com/testinggo v1.1.2 h1:/zCBvslySEY4uJ2qnnyvhFdgIERa/jzlgHBOmS4lL1k= -aletheiaware.com/testinggo v1.1.2/go.mod h1:bqmrqRyMkGbTa9E/1D8xHE0KLmOw+HRG0skc/XwrdcY= -fyne.io/fyne/v2 v2.0.0 h1:TfsS3bNq5663BpXsoz1OfzyjcaMqqOf9usI8ZKkw4IE= -fyne.io/fyne/v2 v2.0.0/go.mod h1:FmobqvPpBW+nG1nDyxZWf1SQLED9g/vXIxiIIVjHazY= -github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9 h1:1ltqoej5GtaWF8jaiA49HwsZD459jqm9YFz9ZtMFpQA= +aletheiaware.com/aliasgo v1.2.3 h1:joMErbHdyo+jVbIoA9HWMPmUVfhZjabBVaB5AnYYObQ= +aletheiaware.com/aliasgo v1.2.3/go.mod h1:wSp0m2ZOXA3M3ZKFcUtcf2ANBio5JSXxQx07IpxwaGM= +aletheiaware.com/bcclientgo v1.2.3 h1:bkUjPmDCQIajTHEKveziyxq/StvBCCoOfSmwxfTqobg= +aletheiaware.com/bcclientgo v1.2.3/go.mod h1:ZUl59XyDsLGYqumzo2woBKhqVv9zjgoa/UQqFF8NPV4= +aletheiaware.com/bcfynego v1.2.3 h1:e8/UByeMavPyseR83Loo6LOEW8cR6ezgLXArduxH5zI= +aletheiaware.com/bcfynego v1.2.3/go.mod h1:5wYg/kMnceZQWescJTUZ9lT4ob3WOMn1/6ECx5VYT3o= +aletheiaware.com/bcgo v1.2.3 h1:5vRjjrkmlSh0/cwhY5u+0S4RUpvTCAMN1HVJMBl9A88= +aletheiaware.com/bcgo v1.2.3/go.mod h1:zNPBDrox6aUVv8ns5UOzcaDXzD/p5tZ0lGSxlfT6/Rs= +aletheiaware.com/cryptogo v1.2.2 h1:d7vEEgf3bZFnLk+HG1wCAY/pgRz+zNYvKFpxsli3Mng= +aletheiaware.com/cryptogo v1.2.2/go.mod h1:B1mJVIsfEDJoovkD2fLsZXgXxR1AAe2cDmjFwt7Eau4= +aletheiaware.com/financego v1.2.3 h1:0pDUPPSEcRbzKGR9HTvcrMQ7/anUs4EByub+yB/Unvo= +aletheiaware.com/financego v1.2.3/go.mod h1:wSeFDTfW+2OaOt5AEo8OGAfXpaQrU7+VraFxR1X5i4Q= +aletheiaware.com/spaceclientgo v1.2.4 h1:6CwANEdUBXSuNu9moFj82Loh5idi4O3CPW6OVTaDJhA= +aletheiaware.com/spaceclientgo v1.2.4/go.mod h1:jW1BWXiBS23Gwj354+BHZH+ojChQ/fzURgMHuE80ZO8= +aletheiaware.com/spacefynego v1.2.4 h1:yc6tmbAEaqAQxKdPVifk/wSM1sgUmS5VOY28svaC82M= +aletheiaware.com/spacefynego v1.2.4/go.mod h1:AtYfVwqITQRkgm3YIBoW6GZw8XArV4DO+PmLW77bueI= +aletheiaware.com/spacego v1.2.4 h1:P08ld8gDaBA0cjBtsVt/hqVqQSgh/gGnrVthYy+aBWA= +aletheiaware.com/spacego v1.2.4/go.mod h1:lWj2RCxdTqwLLCbDbIhiYlO5J+nRM3RldYvLxbLwQ9w= +aletheiaware.com/testinggo v1.2.2 h1:w+ir8ehcnIcZ+jTjalGWAkh3So9PaJm5g3CPgLnPtXE= +aletheiaware.com/testinggo v1.2.2/go.mod h1:TijVTRIGnue9UHlxT9YgLp5VGWOo4PI9VRflCm4v4xo= +fyne.io/fyne/v2 v2.0.2 h1:6pDvFuCmL1odyT/fPI+2L54hMJW1Zt9Dno41HmLInRs= +fyne.io/fyne/v2 v2.0.2/go.mod h1:3+FYmLJVgeb8EvTPJ5YzZeo7LkAq4bbuY3Zrir6xHbg= github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I= -github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -31,42 +29,31 @@ github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8 github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fyne-io/mobile v0.1.2 h1:0HaXDtOOwyOTn3Umi0uKVCOgJtfX73c6unC4U8i5VZU= -github.com/fyne-io/mobile v0.1.2/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY= +github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f h1:rguJ/t99j/6zRSFzsBKlsmmyl+vOvCeTJ+2uTBvuXFI= +github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY= github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw= github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3 h1:q521PfSp5/z6/sD9FZZOWj4d1MLmfQW8PkRnI9M6PCE= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48 h1:QrUfZrT8n72FUuiABt4tbu8PwDnOPAbnj3Mql1UhdRI= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8= github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw= -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.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526 h1:NfuKjkj/Xc2z1xZIj+EmNCm5p1nKJPyw3F4E20usXvg= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc= -github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca h1:ozPUX9TKQZVek4lZWYRsQo7uS8vJ+q4OOHvRhHiCLfU= github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lucor/goinfo v0.0.0-20200401173949-526b5363a13a h1:4djPngMU3ttoFCf6DOgPNQYmxyNmRRmpLg4/uz2TTEg= github.com/lucor/goinfo v0.0.0-20200401173949-526b5363a13a/go.mod h1:ORP3/rB5IsulLEBwQZCJyyV6niqmI7P4EWSmkug+1Ng= -github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -78,7 +65,6 @@ github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCE github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -87,56 +73,49 @@ github.com/stripe/stripe-go v70.15.0+incompatible/go.mod h1:A1dQZmO/QypXmsL0T8ax github.com/yuin/goldmark v1.1.25/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-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc h1:+q90ECDSAQirdykUN6sPEiBXBsp8Csjcca8Oy7bgLTA= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= +golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk= +golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666 h1:gVCS+QOncANNPlmlO1AhlU3oxs4V9z+gTtPwIk3p2N8= golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +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.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/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-20200328031815-3db5fc6bac03 h1:XpToik3MpT5iW3iHgNwnh3a8QwugfomvxOlyDnaOils= golang.org/x/tools v0.0.0-20200328031815-3db5fc6bac03/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/ui/thumbnails_space.go b/ui/thumbnails_space.go index e0438d1..e94476f 100644 --- a/ui/thumbnails_space.go +++ b/ui/thumbnails_space.go @@ -22,13 +22,13 @@ import ( type SpaceThumbnailTable struct { *thumbnailTable - client *spaceclientgo.SpaceClient - node *bcgo.Node + client spaceclientgo.SpaceClient + node bcgo.Node metas map[string]*spacego.Meta timestamps map[string]uint64 } -func NewSpaceThumbnailTable(client *spaceclientgo.SpaceClient, callback func(id string, timestamp uint64, meta *spacego.Meta)) *SpaceThumbnailTable { +func NewSpaceThumbnailTable(client spaceclientgo.SpaceClient, callback func(id string, timestamp uint64, meta *spacego.Meta)) *SpaceThumbnailTable { t := &SpaceThumbnailTable{ thumbnailTable: newThumbnailTable(), client: client, @@ -89,9 +89,9 @@ func (t *SpaceThumbnailTable) Clear() { t.Refresh() } -func (t *SpaceThumbnailTable) Update(node *bcgo.Node) error { +func (t *SpaceThumbnailTable) Update(node bcgo.Node) error { t.node = node - if err := t.client.List(node, t.AddMeta); err != nil { + if err := t.client.AllMetas(node, t.AddMeta); err != nil { return err } t.Refresh() diff --git a/vendor/aletheiaware.com/aliasgo/alias.go b/vendor/aletheiaware.com/aliasgo/alias.go index 74e0a2e..607f5ac 100644 --- a/vendor/aletheiaware.com/aliasgo/alias.go +++ b/vendor/aletheiaware.com/aliasgo/alias.go @@ -18,10 +18,12 @@ package aliasgo import ( "aletheiaware.com/bcgo" + "aletheiaware.com/bcgo/channel" + "aletheiaware.com/bcgo/identity" + "aletheiaware.com/bcgo/validation" "aletheiaware.com/cryptogo" "crypto/rsa" "encoding/base64" - "errors" "fmt" "github.com/golang/protobuf/proto" "log" @@ -39,27 +41,14 @@ const ( MAX_ALIAS_LENGTH = 100 MIN_ALIAS_LENGTH = 1 - - ERROR_ALIAS_ALREADY_REGISTERED = "Alias Already Registered: %s" - ERROR_ALIAS_INVALID = "Alias Invalid: %s" - ERROR_ALIAS_NOT_FOUND = "Could Not Find Alias For Public Key" - ERROR_ALIAS_NOT_PUBLIC = "Cannot Register Private Alias" - ERROR_ALIAS_TOO_LONG = "Alias Too Long: %d Maximum: %d" - ERROR_ALIAS_TOO_SHORT = "Alias Too Short: %d Minimum: %d" - ERROR_PUBLIC_KEY_NOT_FOUND = "Could Not Find Public Key For Alias" ) -func OpenAliasChannel() *bcgo.Channel { - return &bcgo.Channel{ - Name: ALIAS, - Validators: []bcgo.Validator{ - &bcgo.LiveValidator{}, - &bcgo.PoWValidator{ - Threshold: ALIAS_THRESHOLD, - }, - &AliasValidator{}, - }, - } +func OpenAliasChannel() bcgo.Channel { + c := channel.New(ALIAS) + c.AddValidator(&validation.Live{}) + c.AddValidator(validation.NewPoW(ALIAS_THRESHOLD)) + c.AddValidator(&AliasValidator{}) + return c } // Validates alias is the correct length and all characters are in the set [a-zA-Z0-9.-_] @@ -67,20 +56,20 @@ func ValidateAlias(alias string) error { if strings.IndexFunc(alias, func(r rune) bool { return !unicode.IsLetter(r) && !unicode.IsDigit(r) && r != '.' && r != '-' && r != '_' }) != -1 { - return fmt.Errorf(ERROR_ALIAS_INVALID, alias) + return ErrAliasInvalid{Alias: alias} } length := len(alias) if length < MIN_ALIAS_LENGTH { - return fmt.Errorf(ERROR_ALIAS_TOO_SHORT, length, MIN_ALIAS_LENGTH) + return ErrAliasTooShort{Size: length, Min: MIN_ALIAS_LENGTH} } if length > MAX_ALIAS_LENGTH { - return fmt.Errorf(ERROR_ALIAS_TOO_LONG, length, MAX_ALIAS_LENGTH) + return ErrAliasTooLong{Size: length, Max: MAX_ALIAS_LENGTH} } return nil } -func UniqueAlias(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alias string) error { - return bcgo.Iterate(channel.Name, channel.Head, nil, cache, network, func(hash []byte, block *bcgo.Block) error { +func UniqueAlias(channel bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alias string) error { + return bcgo.Iterate(channel.Name(), channel.Head(), nil, cache, network, func(hash []byte, block *bcgo.Block) error { for _, entry := range block.Entry { record := entry.Record if record.Creator == alias { @@ -90,7 +79,7 @@ func UniqueAlias(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, return err } if a.Alias == alias { - return fmt.Errorf(ERROR_ALIAS_ALREADY_REGISTERED, alias) + return ErrAliasAlreadyRegistered{Alias: alias} } } } @@ -98,8 +87,8 @@ func UniqueAlias(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, }) } -func IterateAliases(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, callback func(*bcgo.BlockEntry, *Alias) error) error { - return bcgo.Iterate(channel.Name, channel.Head, nil, cache, network, func(hash []byte, block *bcgo.Block) error { +func IterateAliases(channel bcgo.Channel, cache bcgo.Cache, network bcgo.Network, callback func(*bcgo.BlockEntry, *Alias) error) error { + return bcgo.Iterate(channel.Name(), channel.Head(), nil, cache, network, func(hash []byte, block *bcgo.Block) error { for _, entry := range block.Entry { alias := &Alias{} err := proto.Unmarshal(entry.Record.Payload, alias) @@ -115,9 +104,9 @@ func IterateAliases(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Networ }) } -func GetAlias(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, publicKey *rsa.PublicKey) (*Alias, error) { +func AliasForKey(channel bcgo.Channel, cache bcgo.Cache, network bcgo.Network, publicKey *rsa.PublicKey) (*Alias, error) { var result *Alias - if err := bcgo.Iterate(channel.Name, channel.Head, nil, cache, network, func(hash []byte, block *bcgo.Block) error { + if err := bcgo.Iterate(channel.Name(), channel.Head(), nil, cache, network, func(hash []byte, block *bcgo.Block) error { for _, entry := range block.Entry { record := entry.Record a := &Alias{} @@ -125,19 +114,19 @@ func GetAlias(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, pub if err != nil { return err } - pk, err := cryptogo.ParseRSAPublicKey(a.PublicKey, a.PublicFormat) + pk, err := cryptogo.ParseRSAPublicKey(a.PublicFormat, a.PublicKey) if err != nil { return err } if publicKey.N.Cmp(pk.N) == 0 && publicKey.E == pk.E { result = a - return bcgo.StopIterationError{} + return bcgo.ErrStopIteration{} } } return nil }); err != nil { switch err.(type) { - case bcgo.StopIterationError: + case bcgo.ErrStopIteration: // Do nothing break default: @@ -145,14 +134,14 @@ func GetAlias(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, pub } } if result == nil { - return nil, errors.New(ERROR_ALIAS_NOT_FOUND) + return nil, ErrAliasNotFound{} } return result, nil } -func GetPublicKey(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alias string) (*rsa.PublicKey, error) { +func PublicKeyForAlias(channel bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alias string) (*rsa.PublicKey, error) { var result *rsa.PublicKey - if err := bcgo.Iterate(channel.Name, channel.Head, nil, cache, network, func(hash []byte, block *bcgo.Block) error { + if err := bcgo.Iterate(channel.Name(), channel.Head(), nil, cache, network, func(hash []byte, block *bcgo.Block) error { for _, entry := range block.Entry { record := entry.Record a := &Alias{} @@ -161,17 +150,17 @@ func GetPublicKey(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, return err } if a.Alias == alias { - result, err = cryptogo.ParseRSAPublicKey(a.PublicKey, a.PublicFormat) + result, err = cryptogo.ParseRSAPublicKey(a.PublicFormat, a.PublicKey) if err != nil { return err } - return bcgo.StopIterationError{} + return bcgo.ErrStopIteration{} } } return nil }); err != nil { switch err.(type) { - case bcgo.StopIterationError: + case bcgo.ErrStopIteration: // Do nothing break default: @@ -179,41 +168,55 @@ func GetPublicKey(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, } } if result == nil { - return nil, errors.New(ERROR_PUBLIC_KEY_NOT_FOUND) + return nil, ErrPublicKeyNotFound{Alias: alias} } return result, nil } -func GetPublicKeys(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, addresses []string) map[string]*rsa.PublicKey { - acl := make(map[string]*rsa.PublicKey) - if len(addresses) > 0 { +func PublicKeysForAliases(channel bcgo.Channel, cache bcgo.Cache, network bcgo.Network, aliases []string) (access []bcgo.Identity) { + if len(aliases) > 0 { alias := &Alias{} - bcgo.Iterate(channel.Name, channel.Head, nil, cache, network, func(hash []byte, block *bcgo.Block) error { + bcgo.Iterate(channel.Name(), channel.Head(), nil, cache, network, func(hash []byte, block *bcgo.Block) error { for _, entry := range block.Entry { err := proto.Unmarshal(entry.Record.Payload, alias) if err != nil { return err } - for _, address := range addresses { - if alias.Alias == address { - publicKey, err := cryptogo.ParseRSAPublicKey(alias.PublicKey, alias.PublicFormat) + for _, a := range aliases { + if alias.Alias == a { + publicKey, err := cryptogo.ParseRSAPublicKey(alias.PublicFormat, alias.PublicKey) if err != nil { return err } - acl[address] = publicKey + access = append(access, identity.NewRSA(a, publicKey)) } } } return nil }) } - return acl + return +} + +func AllPublicKeys(channel bcgo.Channel, cache bcgo.Cache, network bcgo.Network) (map[string]*rsa.PublicKey, error) { + aliases := make(map[string]*rsa.PublicKey) + if err := IterateAliases(channel, cache, network, func(e *bcgo.BlockEntry, a *Alias) error { + key, err := cryptogo.ParseRSAPublicKey(a.PublicFormat, a.PublicKey) + if err != nil { + return err + } + aliases[a.Alias] = key + return nil + }); err != nil { + return nil, err + } + return aliases, nil } -func GetRecord(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alias string) (*bcgo.Record, *Alias, error) { +func Record(channel bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alias string) (*bcgo.Record, *Alias, error) { var recordResult *bcgo.Record var aliasResult *Alias - if err := bcgo.Iterate(channel.Name, channel.Head, nil, cache, network, func(hash []byte, block *bcgo.Block) error { + if err := bcgo.Iterate(channel.Name(), channel.Head(), nil, cache, network, func(hash []byte, block *bcgo.Block) error { for _, entry := range block.Entry { record := entry.Record if record.Creator == alias { @@ -223,13 +226,13 @@ func GetRecord(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, al if err != nil { return err } - return bcgo.StopIterationError{} + return bcgo.ErrStopIteration{} } } return nil }); err != nil { switch err.(type) { - case bcgo.StopIterationError: + case bcgo.ErrStopIteration: // Do nothing break default: @@ -237,7 +240,7 @@ func GetRecord(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, al } } if recordResult == nil || aliasResult == nil { - return nil, nil, errors.New(ERROR_ALIAS_NOT_FOUND) + return nil, nil, ErrAliasNotFound{} } return recordResult, aliasResult, nil } @@ -245,13 +248,13 @@ func GetRecord(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, al type AliasValidator struct { } -func (a *AliasValidator) Validate(channel *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, hash []byte, block *bcgo.Block) error { +func (a *AliasValidator) Validate(channel bcgo.Channel, cache bcgo.Cache, network bcgo.Network, hash []byte, block *bcgo.Block) error { register := make(map[string]bool) - return bcgo.Iterate(channel.Name, hash, block, cache, network, func(h []byte, b *bcgo.Block) error { + return bcgo.Iterate(channel.Name(), hash, block, cache, network, func(h []byte, b *bcgo.Block) error { for _, entry := range b.Entry { record := entry.Record if len(record.Access) != 0 { - return fmt.Errorf(ERROR_ALIAS_NOT_PUBLIC) + return ErrAliasNotPublic{} } a := &Alias{} err := proto.Unmarshal(record.Payload, a) @@ -263,7 +266,7 @@ func (a *AliasValidator) Validate(channel *bcgo.Channel, cache bcgo.Cache, netwo } v, exists := register[a.Alias] if exists || v { - return fmt.Errorf(ERROR_ALIAS_ALREADY_REGISTERED, a.Alias) + return ErrAliasAlreadyRegistered{Alias: a.Alias} } register[a.Alias] = true } @@ -271,82 +274,86 @@ func (a *AliasValidator) Validate(channel *bcgo.Channel, cache bcgo.Cache, netwo }) } -func Register(node *bcgo.Node, listener bcgo.MiningListener) error { +func Register(node bcgo.Node, listener bcgo.MiningListener) error { + account := node.Account() + alias := account.Alias() + cache := node.Cache() + network := node.Network() // Open Alias Channel aliases := OpenAliasChannel() - if err := aliases.Refresh(node.Cache, node.Network); err != nil { + if err := aliases.Refresh(cache, network); err != nil { log.Println(err) } - if err := ValidateAlias(node.Alias); err != nil { + if err := ValidateAlias(alias); err != nil { return err } // Check Alias is unique - if err := UniqueAlias(aliases, node.Cache, node.Network, node.Alias); err != nil { + if err := UniqueAlias(aliases, cache, network, alias); err != nil { return err } // Register Alias - if err := RegisterAlias(bcgo.GetBCWebsite(), node.Alias, node.Key); err != nil { + if err := RegisterAlias(bcgo.BCWebsite(), account); err != nil { log.Println("Could not register alias remotely:", err) log.Println("Registering locally") // Create record - record, err := CreateSignedAliasRecord(node.Alias, node.Key) + record, err := CreateSignedAliasRecord(account) if err != nil { return err } // Write record to cache - if _, err := bcgo.WriteRecord(ALIAS, node.Cache, record); err != nil { + if _, err := bcgo.WriteRecord(ALIAS, cache, record); err != nil { return err } // Mine record into blockchain - if _, _, err := node.Mine(aliases, ALIAS_THRESHOLD, listener); err != nil { + if _, _, err := bcgo.Mine(node, aliases, ALIAS_THRESHOLD, listener); err != nil { return err } // Push update to peers - if err := aliases.Push(node.Cache, node.Network); err != nil { + if err := aliases.Push(cache, network); err != nil { return err } } return nil } -func CreateSignedAliasRecord(alias string, privateKey *rsa.PrivateKey) (*bcgo.Record, error) { +func CreateSignedAliasRecord(account bcgo.Account) (*bcgo.Record, error) { + alias := account.Alias() if err := ValidateAlias(alias); err != nil { return nil, err } - publicKeyBytes, err := cryptogo.RSAPublicKeyToPKIXBytes(&privateKey.PublicKey) + publicKeyFormat, publicKey, err := account.PublicKey() if err != nil { return nil, err } - publicKeyFormat := cryptogo.PublicKeyFormat_PKIX - hash, err := cryptogo.HashProtobuf(&Alias{ + a := &Alias{ Alias: alias, - PublicKey: publicKeyBytes, + PublicKey: publicKey, PublicFormat: publicKeyFormat, - }) + } + data, err := proto.Marshal(a) if err != nil { return nil, err } - signatureAlgorithm := cryptogo.SignatureAlgorithm_SHA512WITHRSA_PSS - signature, err := cryptogo.CreateSignature(privateKey, hash, signatureAlgorithm) + algorithm, signature, err := account.Sign(data) if err != nil { return nil, err } - return CreateAliasRecord(alias, publicKeyBytes, publicKeyFormat, signature, signatureAlgorithm) + return CreateAliasRecord(alias, publicKeyFormat, publicKey, algorithm, signature) } -func CreateAliasRecord(alias string, publicKey []byte, publicKeyFormat cryptogo.PublicKeyFormat, signature []byte, signatureAlgorithm cryptogo.SignatureAlgorithm) (*bcgo.Record, error) { +func CreateAliasRecord(alias string, publicKeyFormat cryptogo.PublicKeyFormat, publicKey []byte, signatureAlgorithm cryptogo.SignatureAlgorithm, signature []byte) (*bcgo.Record, error) { if err := ValidateAlias(alias); err != nil { return nil, err } - pubKey, err := cryptogo.ParseRSAPublicKey(publicKey, publicKeyFormat) + pubKey, err := cryptogo.ParseRSAPublicKey(publicKeyFormat, publicKey) if err != nil { return nil, err } @@ -361,7 +368,7 @@ func CreateAliasRecord(alias string, publicKey []byte, publicKeyFormat cryptogo. return nil, err } - if err := cryptogo.VerifySignature(pubKey, cryptogo.Hash(data), signature, signatureAlgorithm); err != nil { + if err := cryptogo.VerifySignature(signatureAlgorithm, pubKey, cryptogo.Hash(data), signature); err != nil { return nil, err } @@ -381,38 +388,36 @@ func CreateAliasRecord(alias string, publicKey []byte, publicKeyFormat cryptogo. return record, nil } -func RegisterAlias(host, alias string, key *rsa.PrivateKey) error { +func RegisterAlias(host string, account bcgo.Account) error { + alias := account.Alias() if err := ValidateAlias(alias); err != nil { return err } - publicKeyBytes, err := cryptogo.RSAPublicKeyToPKIXBytes(&key.PublicKey) + publicKeyFormat, publicKey, err := account.PublicKey() if err != nil { return err } data, err := proto.Marshal(&Alias{ Alias: alias, - PublicKey: publicKeyBytes, - PublicFormat: cryptogo.PublicKeyFormat_PKIX, + PublicKey: publicKey, + PublicFormat: publicKeyFormat, }) if err != nil { return err } - - signatureAlgorithm := cryptogo.SignatureAlgorithm_SHA512WITHRSA_PSS - - signature, err := cryptogo.CreateSignature(key, cryptogo.Hash(data), signatureAlgorithm) + algorithm, signature, err := account.Sign(data) if err != nil { return err } response, err := http.PostForm(host+"/alias-register", url.Values{ "alias": {alias}, - "publicKey": {base64.RawURLEncoding.EncodeToString(publicKeyBytes)}, - "publicKeyFormat": {"PKIX"}, + "publicKey": {base64.RawURLEncoding.EncodeToString(publicKey)}, + "publicKeyFormat": {publicKeyFormat.String()}, "signature": {base64.RawURLEncoding.EncodeToString(signature)}, - "signatureAlgorithm": {signatureAlgorithm.String()}, + "signatureAlgorithm": {algorithm.String()}, }) if err != nil { return err diff --git a/vendor/aletheiaware.com/aliasgo/errors.go b/vendor/aletheiaware.com/aliasgo/errors.go new file mode 100644 index 0000000..33e7f64 --- /dev/null +++ b/vendor/aletheiaware.com/aliasgo/errors.go @@ -0,0 +1,80 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package aliasgo + +import "fmt" + +// ErrAliasAlreadyRegistered is returned if the alias being registered is already taken. +type ErrAliasAlreadyRegistered struct { + Alias string +} + +func (e ErrAliasAlreadyRegistered) Error() string { + return fmt.Sprintf("Alias Already Registered: %s", e.Alias) +} + +// ErrAliasInvalid is returned when the alias includes unsupported characters. +type ErrAliasInvalid struct { + Alias string +} + +func (e ErrAliasInvalid) Error() string { + return fmt.Sprintf("Alias Invalid: %s", e.Alias) +} + +// ErrAliasNotFound is returned if the alias cannot be found. +type ErrAliasNotFound struct { +} + +func (e ErrAliasNotFound) Error() string { + return fmt.Sprintf("Could Not Find Alias For Public Key") +} + +// ErrAliasNotPublic is returned when registering an encrypted alias. +type ErrAliasNotPublic struct { +} + +func (e ErrAliasNotPublic) Error() string { + return fmt.Sprintf("Cannot Register Private Alias") +} + +// ErrAliasTooLong is returned when the alias is too long. +type ErrAliasTooLong struct { + Size, Max int +} + +func (e ErrAliasTooLong) Error() string { + return fmt.Sprintf("Alias Too Long: %d Maximum: %d", e.Size, e.Max) +} + +// ErrAliasTooShort is returned when the alias is too short. +type ErrAliasTooShort struct { + Size, Min int +} + +func (e ErrAliasTooShort) Error() string { + return fmt.Sprintf("Alias Too Short: %d Minimum: %d", e.Size, e.Min) +} + +// ErrPublicKeyNotFound is return if the public key cannot be found. +type ErrPublicKeyNotFound struct { + Alias string +} + +func (e ErrPublicKeyNotFound) Error() string { + return fmt.Sprintf("Could Not Find Public Key For Alias: %s", e.Alias) +} diff --git a/vendor/aletheiaware.com/aliasgo/go.mod b/vendor/aletheiaware.com/aliasgo/go.mod index 15ccbe3..3dd0619 100644 --- a/vendor/aletheiaware.com/aliasgo/go.mod +++ b/vendor/aletheiaware.com/aliasgo/go.mod @@ -3,8 +3,8 @@ module aletheiaware.com/aliasgo go 1.14 require ( - aletheiaware.com/bcgo v1.1.4 - aletheiaware.com/cryptogo v1.1.1 - aletheiaware.com/testinggo v1.1.2 - github.com/golang/protobuf v1.4.3 + aletheiaware.com/bcgo v1.2.3 + aletheiaware.com/cryptogo v1.2.2 + aletheiaware.com/testinggo v1.2.2 + github.com/golang/protobuf v1.5.2 ) diff --git a/vendor/aletheiaware.com/aliasgo/go.sum b/vendor/aletheiaware.com/aliasgo/go.sum index 153cda5..5749a66 100644 --- a/vendor/aletheiaware.com/aliasgo/go.sum +++ b/vendor/aletheiaware.com/aliasgo/go.sum @@ -1,36 +1,36 @@ -aletheiaware.com/bcgo v1.1.4 h1:HuAk12UeOvtIXlc7WN2XIj9tV+jNA5uCi+D8Z0V2twU= -aletheiaware.com/bcgo v1.1.4/go.mod h1:GXvFFZ8JrATGrvuKA0J3ucf9+91eC94ggphNVpg3XUM= -aletheiaware.com/cryptogo v1.1.1 h1:XrzGXcTgYQbuL3tQv/idVzAIblb2k+o77iigiQiXTUQ= -aletheiaware.com/cryptogo v1.1.1/go.mod h1:sT8jDe5zWSIswZDAilLwfX2N6l4WOFQBm+4lYxx1Ae0= -aletheiaware.com/testinggo v1.1.2 h1:/zCBvslySEY4uJ2qnnyvhFdgIERa/jzlgHBOmS4lL1k= -aletheiaware.com/testinggo v1.1.2/go.mod h1:bqmrqRyMkGbTa9E/1D8xHE0KLmOw+HRG0skc/XwrdcY= -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.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +aletheiaware.com/bcgo v1.2.3 h1:5vRjjrkmlSh0/cwhY5u+0S4RUpvTCAMN1HVJMBl9A88= +aletheiaware.com/bcgo v1.2.3/go.mod h1:zNPBDrox6aUVv8ns5UOzcaDXzD/p5tZ0lGSxlfT6/Rs= +aletheiaware.com/cryptogo v1.2.2 h1:d7vEEgf3bZFnLk+HG1wCAY/pgRz+zNYvKFpxsli3Mng= +aletheiaware.com/cryptogo v1.2.2/go.mod h1:B1mJVIsfEDJoovkD2fLsZXgXxR1AAe2cDmjFwt7Eau4= +aletheiaware.com/testinggo v1.2.2 h1:w+ir8ehcnIcZ+jTjalGWAkh3So9PaJm5g3CPgLnPtXE= +aletheiaware.com/testinggo v1.2.2/go.mod h1:TijVTRIGnue9UHlxT9YgLp5VGWOo4PI9VRflCm4v4xo= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc h1:+q90ECDSAQirdykUN6sPEiBXBsp8Csjcca8Oy7bgLTA= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/aletheiaware.com/bcclientgo/README.md b/vendor/aletheiaware.com/bcclientgo/README.md index 0884f3d..77031dc 100644 --- a/vendor/aletheiaware.com/bcclientgo/README.md +++ b/vendor/aletheiaware.com/bcclientgo/README.md @@ -15,9 +15,8 @@ This is a Go implementation of a BC client using the BC data structures. Install the binary (or download from https://github.com/AletheiaWareLLC/bcclientgo/releases/latest) -``` -go install -tags release aletheiaware.com/bcclientgo/cmd/bc -``` + + go install -tags release aletheiaware.com/bcclientgo/cmd/bc # Usage diff --git a/vendor/aletheiaware.com/bcclientgo/client.go b/vendor/aletheiaware.com/bcclientgo/client.go index 59dfcd7..51fb770 100644 --- a/vendor/aletheiaware.com/bcclientgo/client.go +++ b/vendor/aletheiaware.com/bcclientgo/client.go @@ -19,9 +19,13 @@ package bcclientgo import ( "aletheiaware.com/aliasgo" "aletheiaware.com/bcgo" + "aletheiaware.com/bcgo/account" + "aletheiaware.com/bcgo/cache" + "aletheiaware.com/bcgo/channel" + "aletheiaware.com/bcgo/network" + "aletheiaware.com/bcgo/node" "aletheiaware.com/cryptogo" "bytes" - "crypto/rsa" "encoding/base64" "errors" "fmt" @@ -31,137 +35,188 @@ import ( "reflect" ) -type BCClient struct { - Root string - Peers []string - Cache bcgo.Cache - Network bcgo.Network - Node *bcgo.Node +type BCClient interface { + Root() (string, error) + Peers() []string + Cache() (bcgo.Cache, error) + Network() (bcgo.Network, error) + Account() (bcgo.Account, error) + Node() (bcgo.Node, error) + + HasCache() bool + HasNetwork() bool + HasAccount() bool + HasNode() bool + + PublicKey(string) (cryptogo.PublicKeyFormat, []byte, error) + Head(string) ([]byte, error) + Chain(string, func([]byte, *bcgo.Block) error) error + Block(string, []byte) (*bcgo.Block, error) + Record(string, []byte) (*bcgo.Record, error) + Read(string, []byte, []byte, io.Writer) error + ReadKey(string, []byte, []byte, io.Writer) error + ReadPayload(string, []byte, []byte, io.Writer) error + Write(string, []string, io.Reader) (int, error) + Mine(string, uint64, bcgo.MiningListener) ([]byte, error) + Pull(string) error + Push(string) error + Purge() error + + ImportKeys(string, string, string) error + ExportKeys(string, string, []byte) (string, error) + + SetRoot(string) + SetPeers(...string) + SetCache(bcgo.Cache) + SetNetwork(bcgo.Network) + SetAccount(bcgo.Account) + SetNode(bcgo.Node) } -func NewBCClient(peers ...string) *BCClient { +type bcClient struct { + root string + peers []string + cache bcgo.Cache + network bcgo.Network + account bcgo.Account + node bcgo.Node +} + +func NewBCClient(peers ...string) BCClient { /* TODO try loading from file system - rootDir, err := c.GetRoot() + rootDir, err := c.Root() if err == nil { - bcgo.GetPeers(rootDir) + bcgo.Peers(rootDir) } */ if len(peers) == 0 { peers = append(peers, - bcgo.GetBCHost(), // Add BC host as peer + bcgo.BCHost(), // Add BC host as peer ) } - return &BCClient{ - Peers: peers, + return &bcClient{ + peers: peers, } } -func (c *BCClient) GetPeers() ([]string, error) { - return c.Peers, nil +func (c *bcClient) Peers() []string { + return c.peers } -func (c *BCClient) GetCache() (bcgo.Cache, error) { - if c.Cache == nil { - rootDir, err := c.GetRoot() +func (c *bcClient) Cache() (bcgo.Cache, error) { + if c.cache == nil { + rootDir, err := c.Root() if err != nil { return nil, err } - cacheDir, err := bcgo.GetCacheDirectory(rootDir) + cacheDir, err := bcgo.CacheDirectory(rootDir) if err != nil { return nil, fmt.Errorf("Could not get cache directory: %s", err.Error()) } - cache, err := bcgo.NewFileCache(cacheDir) + cache, err := cache.NewFileSystem(cacheDir) if err != nil { return nil, fmt.Errorf("Could not create file cache: %s", err.Error()) } - c.Cache = cache + c.cache = cache } - return c.Cache, nil + return c.cache, nil } -func (c *BCClient) GetNetwork() (bcgo.Network, error) { - if c.Network == nil || reflect.ValueOf(c.Network).IsNil() { - peers, err := c.GetPeers() - if err != nil { - return nil, err - } - c.Network = bcgo.NewTCPNetwork(peers...) +func (c *bcClient) Network() (bcgo.Network, error) { + if c.network == nil || reflect.ValueOf(c.network).IsNil() { + c.network = network.NewTCP(c.Peers()...) } - return c.Network, nil + return c.network, nil } -func (c *BCClient) GetNode() (*bcgo.Node, error) { - if c.Node == nil { - rootDir, err := c.GetRoot() +func (c *bcClient) Account() (bcgo.Account, error) { + if !c.HasAccount() { + rootDir, err := c.Root() if err != nil { return nil, err } - cache, err := c.GetCache() + account, err := account.LoadRSA(rootDir) if err != nil { return nil, err } - network, err := c.GetNetwork() + c.account = account + } + return c.account, nil +} + +func (c *bcClient) Node() (bcgo.Node, error) { + if !c.HasNode() { + cache, err := c.Cache() + if err != nil { + return nil, err + } + network, err := c.Network() if err != nil { return nil, err } - node, err := bcgo.NewNode(rootDir, cache, network) + account, err := c.Account() if err != nil { return nil, err } - c.Node = node + c.node = node.New(account, cache, network) } - return c.Node, nil + return c.node, nil } -func (c *BCClient) SetRoot(root string) { - c.Root = root +func (c *bcClient) SetRoot(root string) { + c.root = root } -func (c *BCClient) SetPeers(peers ...string) { - c.Peers = peers - if c.Network == nil || reflect.ValueOf(c.Network).IsNil() { +func (c *bcClient) SetPeers(peers ...string) { + c.peers = peers + if c.network == nil || reflect.ValueOf(c.network).IsNil() { return } - if n, ok := c.Network.(*bcgo.TCPNetwork); ok { + if n, ok := c.network.(*network.TCP); ok { n.SetPeers(peers...) } } -func (c *BCClient) SetCache(cache bcgo.Cache) { - c.Cache = cache +func (c *bcClient) SetCache(cache bcgo.Cache) { + c.cache = cache } -func (c *BCClient) SetNetwork(network bcgo.Network) { - c.Network = network +func (c *bcClient) SetNetwork(network bcgo.Network) { + c.network = network } -func (c *BCClient) SetNode(node *bcgo.Node) { - c.Node = node +func (c *bcClient) SetAccount(account bcgo.Account) { + c.account = account } -func (c *BCClient) Init(listener bcgo.MiningListener) (*bcgo.Node, error) { - // Create Node - node, err := c.GetNode() - if err != nil { - return nil, err - } +func (c *bcClient) SetNode(node bcgo.Node) { + c.node = node +} - // Register Alias - if err := aliasgo.Register(node, listener); err != nil { - return nil, err - } +func (c *bcClient) HasCache() bool { + return c.cache != nil && !reflect.ValueOf(c.cache).IsNil() +} + +func (c *bcClient) HasNetwork() bool { + return c.network != nil && !reflect.ValueOf(c.network).IsNil() +} - return node, nil +func (c *bcClient) HasAccount() bool { + return c.account != nil && !reflect.ValueOf(c.account).IsNil() } -func (c *BCClient) Alias(alias string) (string, error) { - cache, err := c.GetCache() +func (c *bcClient) HasNode() bool { + return c.node != nil && !reflect.ValueOf(c.node).IsNil() +} + +func (c *bcClient) PublicKey(alias string) (cryptogo.PublicKeyFormat, []byte, error) { + cache, err := c.Cache() if err != nil { - return "", err + return cryptogo.PublicKeyFormat_UNKNOWN_PUBLIC_KEY_FORMAT, nil, err } - network, err := c.GetNetwork() + network, err := c.Network() if err != nil { - return "", err + return cryptogo.PublicKeyFormat_UNKNOWN_PUBLIC_KEY_FORMAT, nil, err } // Open Alias Channel aliases := aliasgo.OpenAliasChannel() @@ -169,75 +224,75 @@ func (c *BCClient) Alias(alias string) (string, error) { log.Println(err) } // Get Public Key for Alias - publicKey, err := aliasgo.GetPublicKey(aliases, cache, network, alias) + publicKey, err := aliasgo.PublicKeyForAlias(aliases, cache, network, alias) if err != nil { - return "", err + return cryptogo.PublicKeyFormat_UNKNOWN_PUBLIC_KEY_FORMAT, nil, err } publicKeyBytes, err := cryptogo.RSAPublicKeyToPKIXBytes(publicKey) if err != nil { - return "", err + return cryptogo.PublicKeyFormat_UNKNOWN_PUBLIC_KEY_FORMAT, nil, err } - return base64.RawURLEncoding.EncodeToString(publicKeyBytes), nil + return cryptogo.PublicKeyFormat_PKIX, publicKeyBytes, nil } -func (c *BCClient) Head(channel string) ([]byte, error) { - cache, err := c.GetCache() +func (c *bcClient) Head(name string) ([]byte, error) { + cache, err := c.Cache() if err != nil { return nil, err } - network, err := c.GetNetwork() + network, err := c.Network() if err != nil { return nil, err } - ch := bcgo.NewChannel(channel) - if err := ch.LoadHead(cache, network); err != nil { + ch := channel.New(name) + if err := ch.Load(cache, network); err != nil { return nil, err } - return ch.Head, nil + return ch.Head(), nil } -func (c *BCClient) Chain(channel string, callback func([]byte, *bcgo.Block) error) error { - cache, err := c.GetCache() +func (c *bcClient) Chain(name string, callback func([]byte, *bcgo.Block) error) error { + cache, err := c.Cache() if err != nil { return err } - network, err := c.GetNetwork() + network, err := c.Network() if err != nil { return err } - ch := bcgo.NewChannel(channel) - if err := ch.LoadHead(cache, network); err != nil { + ch := channel.New(name) + if err := ch.Load(cache, network); err != nil { return err } - return bcgo.Iterate(channel, ch.Head, nil, cache, network, callback) + return bcgo.Iterate(name, ch.Head(), nil, cache, network, callback) } -func (c *BCClient) Block(channel string, hash []byte) (*bcgo.Block, error) { - cache, err := c.GetCache() +func (c *bcClient) Block(name string, hash []byte) (*bcgo.Block, error) { + cache, err := c.Cache() if err != nil { return nil, err } - network, err := c.GetNetwork() + network, err := c.Network() if err != nil { return nil, err } - block, err := bcgo.GetBlock(channel, cache, network, hash) + block, err := bcgo.LoadBlock(name, cache, network, hash) if err != nil { return nil, err } return block, nil } -func (c *BCClient) Record(channel string, hash []byte) (*bcgo.Record, error) { - cache, err := c.GetCache() +func (c *bcClient) Record(name string, hash []byte) (*bcgo.Record, error) { + cache, err := c.Cache() if err != nil { return nil, err } - network, err := c.GetNetwork() + network, err := c.Network() if err != nil { return nil, err } - block, err := bcgo.GetBlockContainingRecord(channel, cache, network, hash) + block, err := bcgo.LoadBlockContainingRecord(name, cache, network, hash) if err != nil { return nil, err } @@ -249,106 +304,106 @@ func (c *BCClient) Record(channel string, hash []byte) (*bcgo.Record, error) { return nil, errors.New("Could not get block containing record") } -func (c *BCClient) Read(channel string, blockHash, recordHash []byte, output io.Writer) error { - cache, err := c.GetCache() +func (c *bcClient) Read(name string, blockHash, recordHash []byte, output io.Writer) error { + cache, err := c.Cache() if err != nil { return err } - network, err := c.GetNetwork() + network, err := c.Network() if err != nil { return err } - node, err := c.GetNode() + account, err := c.Account() if err != nil { return err } - ch := bcgo.NewChannel(channel) + ch := channel.New(name) - if err := ch.LoadHead(cache, network); err != nil { + if err := ch.Load(cache, network); err != nil { log.Println(err) } if blockHash == nil { - blockHash = ch.Head + blockHash = ch.Head() } - return bcgo.Read(channel, blockHash, nil, cache, network, node.Alias, node.Key, recordHash, func(entry *bcgo.BlockEntry, key, payload []byte) error { + return bcgo.Read(name, blockHash, nil, cache, network, account, recordHash, func(entry *bcgo.BlockEntry, key, payload []byte) error { bcgo.PrintBlockEntry(output, "", entry) return nil }) } -func (c *BCClient) ReadKey(channel string, blockHash, recordHash []byte, output io.Writer) error { - cache, err := c.GetCache() +func (c *bcClient) ReadKey(name string, blockHash, recordHash []byte, output io.Writer) error { + cache, err := c.Cache() if err != nil { return err } - network, err := c.GetNetwork() + network, err := c.Network() if err != nil { return err } - node, err := c.GetNode() + account, err := c.Account() if err != nil { return err } - ch := bcgo.NewChannel(channel) + ch := channel.New(name) - if err := ch.LoadHead(cache, network); err != nil { + if err := ch.Load(cache, network); err != nil { log.Println(err) } if blockHash == nil { - blockHash = ch.Head + blockHash = ch.Head() } - return bcgo.ReadKey(channel, blockHash, nil, cache, network, node.Alias, node.Key, recordHash, func(key []byte) error { + return bcgo.ReadKey(name, blockHash, nil, cache, network, account, recordHash, func(key []byte) error { output.Write(key) return nil }) } -func (c *BCClient) ReadPayload(channel string, blockHash, recordHash []byte, output io.Writer) error { - cache, err := c.GetCache() +func (c *bcClient) ReadPayload(name string, blockHash, recordHash []byte, output io.Writer) error { + cache, err := c.Cache() if err != nil { return err } - network, err := c.GetNetwork() + network, err := c.Network() if err != nil { return err } - node, err := c.GetNode() + account, err := c.Account() if err != nil { return err } - ch := bcgo.NewChannel(channel) + ch := channel.New(name) - if err := ch.LoadHead(cache, network); err != nil { + if err := ch.Load(cache, network); err != nil { log.Println(err) } if blockHash == nil { - blockHash = ch.Head + blockHash = ch.Head() } - return bcgo.Read(channel, blockHash, nil, cache, network, node.Alias, node.Key, recordHash, func(entry *bcgo.BlockEntry, key, payload []byte) error { + return bcgo.Read(name, blockHash, nil, cache, network, account, recordHash, func(entry *bcgo.BlockEntry, key, payload []byte) error { output.Write(payload) return nil }) } -func (c *BCClient) Write(channel string, accesses []string, input io.Reader) (int, error) { - cache, err := c.GetCache() +func (c *bcClient) Write(name string, accesses []string, input io.Reader) (int, error) { + cache, err := c.Cache() if err != nil { return 0, err } - network, err := c.GetNetwork() + network, err := c.Network() if err != nil { return 0, err } - var acl map[string]*rsa.PublicKey + var access []bcgo.Identity if len(accesses) > 0 { // Open Alias Channel @@ -356,16 +411,16 @@ func (c *BCClient) Write(channel string, accesses []string, input io.Reader) (in if err := aliases.Refresh(cache, network); err != nil { log.Println(err) } - acl = aliasgo.GetPublicKeys(aliases, cache, network, accesses) + access = aliasgo.PublicKeysForAliases(aliases, cache, network, accesses) } - node, err := c.GetNode() + account, err := c.Account() if err != nil { return 0, err } - size, err := bcgo.CreateRecords(node.Alias, node.Key, acl, nil, input, func(key []byte, record *bcgo.Record) error { - _, err := bcgo.WriteRecord(channel, cache, record) + size, err := bcgo.CreateRecords(account, access, nil, input, func(key []byte, record *bcgo.Record) error { + _, err := bcgo.WriteRecord(name, cache, record) return err }) if err != nil { @@ -375,113 +430,112 @@ func (c *BCClient) Write(channel string, accesses []string, input io.Reader) (in return size, nil } -func (c *BCClient) Mine(channel string, threshold uint64, listener bcgo.MiningListener) ([]byte, error) { - cache, err := c.GetCache() +func (c *bcClient) Mine(name string, threshold uint64, listener bcgo.MiningListener) ([]byte, error) { + cache, err := c.Cache() if err != nil { return nil, err } - network, err := c.GetNetwork() + network, err := c.Network() if err != nil { return nil, err } - node, err := c.GetNode() + node, err := c.Node() if err != nil { return nil, err } - ch := bcgo.NewChannel(channel) + ch := channel.New(name) - if err := ch.LoadHead(cache, network); err != nil { + if err := ch.Load(cache, network); err != nil { log.Println(err) } - hash, _, err := node.Mine(ch, threshold, listener) + hash, _, err := bcgo.Mine(node, ch, threshold, listener) if err != nil { return nil, err } return hash, nil } -func (c *BCClient) Pull(channel string) error { - cache, err := c.GetCache() +func (c *bcClient) Pull(name string) error { + cache, err := c.Cache() if err != nil { return err } - network, err := c.GetNetwork() + network, err := c.Network() if err != nil { return err } - ch := bcgo.NewChannel(channel) - return ch.Pull(cache, network) + return channel.New(name).Pull(cache, network) } -func (c *BCClient) Push(channel string) error { - cache, err := c.GetCache() +func (c *bcClient) Push(name string) error { + cache, err := c.Cache() if err != nil { return err } - network, err := c.GetNetwork() + network, err := c.Network() if err != nil { return err } - ch := bcgo.NewChannel(channel) - if err := ch.LoadHead(cache, nil); err != nil { + ch := channel.New(name) + if err := ch.Load(cache, nil); err != nil { return err } return ch.Push(cache, network) } -func (c *BCClient) Purge() error { - rootDir, err := c.GetRoot() +func (c *bcClient) Purge() error { + rootDir, err := c.Root() if err != nil { return err } // Get cache directory - dir, err := bcgo.GetCacheDirectory(rootDir) + dir, err := bcgo.CacheDirectory(rootDir) if err != nil { return err } return os.RemoveAll(dir) } -func (c *BCClient) ImportKeys(peer, alias, accessCode string) error { - rootDir, err := c.GetRoot() +func (c *bcClient) ImportKeys(peer, alias, accessCode string) error { + rootDir, err := c.Root() if err != nil { return err } // Get KeyStore - keystore, err := bcgo.GetKeyDirectory(rootDir) + keystore, err := bcgo.KeyDirectory(rootDir) if err != nil { return err } return cryptogo.ImportKeys(peer, keystore, alias, accessCode) } -func (c *BCClient) ExportKeys(peer, alias string, password []byte) (string, error) { - rootDir, err := c.GetRoot() +func (c *bcClient) ExportKeys(peer, alias string, password []byte) (string, error) { + rootDir, err := c.Root() if err != nil { return "", err } // Get KeyStore - keystore, err := bcgo.GetKeyDirectory(rootDir) + keystore, err := bcgo.KeyDirectory(rootDir) if err != nil { return "", err } return cryptogo.ExportKeys(peer, keystore, alias, password) } -func PrintNode(output io.Writer, node *bcgo.Node) error { - fmt.Fprintln(output, node.Alias) - publicKeyBytes, err := cryptogo.RSAPublicKeyToPKIXBytes(&node.Key.PublicKey) +func PrintIdentity(output io.Writer, identity bcgo.Identity) error { + fmt.Fprintln(output, identity.Alias()) + format, bytes, err := identity.PublicKey() if err != nil { return err } - fmt.Fprintln(output, base64.RawURLEncoding.EncodeToString(publicKeyBytes)) + fmt.Fprintln(output, base64.RawURLEncoding.EncodeToString(bytes), format) return nil } func rootDir() (string, error) { - rootDir, err := bcgo.GetRootDirectory() + rootDir, err := bcgo.RootDirectory() if err != nil { return "", fmt.Errorf("Could not get root directory: %s\n", err.Error()) } diff --git a/vendor/aletheiaware.com/bcclientgo/client_android.go b/vendor/aletheiaware.com/bcclientgo/client_android.go index 942e9bd..a253fc9 100644 --- a/vendor/aletheiaware.com/bcclientgo/client_android.go +++ b/vendor/aletheiaware.com/bcclientgo/client_android.go @@ -20,8 +20,8 @@ package bcclientgo import "os" -func (c *BCClient) GetRoot() (string, error) { - if c.Root == "" { +func (c *bcClient) Root() (string, error) { + if c.root == "" { if _, ok := os.LookupEnv("ROOT_DIRECTORY"); !ok { os.Setenv("ROOT_DIRECTORY", os.Getenv("FILESDIR")) } @@ -32,9 +32,9 @@ func (c *BCClient) GetRoot() (string, error) { if err != nil { return "", err } - c.Root = root + c.root = root } - return c.Root, nil + return c.root, nil } //func (c *BCClient) RecordCameraWriteToBC() diff --git a/vendor/aletheiaware.com/bcclientgo/client_desktop.go b/vendor/aletheiaware.com/bcclientgo/client_desktop.go index 750dc6e..086e7c3 100644 --- a/vendor/aletheiaware.com/bcclientgo/client_desktop.go +++ b/vendor/aletheiaware.com/bcclientgo/client_desktop.go @@ -19,13 +19,13 @@ package bcclientgo -func (c *BCClient) GetRoot() (string, error) { - if c.Root == "" { +func (c *bcClient) Root() (string, error) { + if c.root == "" { root, err := rootDir() if err != nil { return "", err } - c.Root = root + c.root = root } - return c.Root, nil + return c.root, nil } diff --git a/vendor/aletheiaware.com/bcclientgo/client_ios.go b/vendor/aletheiaware.com/bcclientgo/client_ios.go index 370c680..c931c62 100644 --- a/vendor/aletheiaware.com/bcclientgo/client_ios.go +++ b/vendor/aletheiaware.com/bcclientgo/client_ios.go @@ -20,8 +20,8 @@ package bcclientgo import "os" -func (c *BCClient) GetRoot() (string, error) { - if c.Root == "" { +func (c *bcClient) Root() (string, error) { + if c.root == "" { if _, ok := os.LookupEnv("ROOT_DIRECTORY"); !ok { homeDir, err := os.UserHomeDir() if err == nil { @@ -38,7 +38,7 @@ func (c *BCClient) GetRoot() (string, error) { if err != nil { return "", err } - c.Root = root + c.root = root } - return c.Root, nil + return c.root, nil } diff --git a/vendor/aletheiaware.com/bcclientgo/go.mod b/vendor/aletheiaware.com/bcclientgo/go.mod index e39e01a..7bce23c 100644 --- a/vendor/aletheiaware.com/bcclientgo/go.mod +++ b/vendor/aletheiaware.com/bcclientgo/go.mod @@ -3,8 +3,8 @@ module aletheiaware.com/bcclientgo go 1.14 require ( - aletheiaware.com/aliasgo v1.1.3 - aletheiaware.com/bcgo v1.1.4 - aletheiaware.com/cryptogo v1.1.1 - aletheiaware.com/testinggo v1.1.2 + aletheiaware.com/aliasgo v1.2.3 + aletheiaware.com/bcgo v1.2.3 + aletheiaware.com/cryptogo v1.2.2 + aletheiaware.com/testinggo v1.2.2 ) diff --git a/vendor/aletheiaware.com/bcclientgo/go.sum b/vendor/aletheiaware.com/bcclientgo/go.sum index b60ad80..e69898c 100644 --- a/vendor/aletheiaware.com/bcclientgo/go.sum +++ b/vendor/aletheiaware.com/bcclientgo/go.sum @@ -1,38 +1,38 @@ -aletheiaware.com/aliasgo v1.1.3 h1:RnJhpWcbH7KWWWgIvUCVS+++mzpjYNk/dQm4o1G0lX8= -aletheiaware.com/aliasgo v1.1.3/go.mod h1:JY9/j4q6ZniHb0vKO7CJJ3M03eTVhczoIIhJBZ6Sa3w= -aletheiaware.com/bcgo v1.1.4 h1:HuAk12UeOvtIXlc7WN2XIj9tV+jNA5uCi+D8Z0V2twU= -aletheiaware.com/bcgo v1.1.4/go.mod h1:GXvFFZ8JrATGrvuKA0J3ucf9+91eC94ggphNVpg3XUM= -aletheiaware.com/cryptogo v1.1.1 h1:XrzGXcTgYQbuL3tQv/idVzAIblb2k+o77iigiQiXTUQ= -aletheiaware.com/cryptogo v1.1.1/go.mod h1:sT8jDe5zWSIswZDAilLwfX2N6l4WOFQBm+4lYxx1Ae0= -aletheiaware.com/testinggo v1.1.2 h1:/zCBvslySEY4uJ2qnnyvhFdgIERa/jzlgHBOmS4lL1k= -aletheiaware.com/testinggo v1.1.2/go.mod h1:bqmrqRyMkGbTa9E/1D8xHE0KLmOw+HRG0skc/XwrdcY= -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.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +aletheiaware.com/aliasgo v1.2.3 h1:joMErbHdyo+jVbIoA9HWMPmUVfhZjabBVaB5AnYYObQ= +aletheiaware.com/aliasgo v1.2.3/go.mod h1:wSp0m2ZOXA3M3ZKFcUtcf2ANBio5JSXxQx07IpxwaGM= +aletheiaware.com/bcgo v1.2.3 h1:5vRjjrkmlSh0/cwhY5u+0S4RUpvTCAMN1HVJMBl9A88= +aletheiaware.com/bcgo v1.2.3/go.mod h1:zNPBDrox6aUVv8ns5UOzcaDXzD/p5tZ0lGSxlfT6/Rs= +aletheiaware.com/cryptogo v1.2.2 h1:d7vEEgf3bZFnLk+HG1wCAY/pgRz+zNYvKFpxsli3Mng= +aletheiaware.com/cryptogo v1.2.2/go.mod h1:B1mJVIsfEDJoovkD2fLsZXgXxR1AAe2cDmjFwt7Eau4= +aletheiaware.com/testinggo v1.2.2 h1:w+ir8ehcnIcZ+jTjalGWAkh3So9PaJm5g3CPgLnPtXE= +aletheiaware.com/testinggo v1.2.2/go.mod h1:TijVTRIGnue9UHlxT9YgLp5VGWOo4PI9VRflCm4v4xo= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc h1:+q90ECDSAQirdykUN6sPEiBXBsp8Csjcca8Oy7bgLTA= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/aletheiaware.com/bcfynego/README.md b/vendor/aletheiaware.com/bcfynego/README.md new file mode 100644 index 0000000..08b146e --- /dev/null +++ b/vendor/aletheiaware.com/bcfynego/README.md @@ -0,0 +1,19 @@ +bcfynego +======== + +This is a Go implementation of a BC client using the BC data structures. + +# About + +`bcfynego` provides a graphical user interface built with the [Fyne](https://fyne.io) toolkit to explore and interact with BC. + +# Build + + go build -tags release + +# Install + +Install the application (or download from https://github.com/AletheiaWareLLC/bcfynego/releases/latest) + + go get fyne.io/fyne + fyne get aletheiaware.com/bcfynego/cmd/bcfyne diff --git a/vendor/aletheiaware.com/bcfynego/build.sh b/vendor/aletheiaware.com/bcfynego/build.sh deleted file mode 100644 index f6489d7..0000000 --- a/vendor/aletheiaware.com/bcfynego/build.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# -# Copyright 2020 Aletheia Ware LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -e -set -x - -protoc bcfyne.proto --go_out=$GOPATH/src/ -go fmt $GOPATH/src/aletheiaware.com/{aliasgo,bcgo,bcclientgo,bcfynego,cryptogo,financego}/... -go test $GOPATH/src/aletheiaware.com/{aliasgo,bcgo,bcclientgo,bcfynego,cryptogo,financego}/... -go build aletheiaware.com/bcfynego diff --git a/vendor/aletheiaware.com/bcfynego/fyne.go b/vendor/aletheiaware.com/bcfynego/fyne.go index 8e56be7..7b1ff1a 100644 --- a/vendor/aletheiaware.com/bcfynego/fyne.go +++ b/vendor/aletheiaware.com/bcfynego/fyne.go @@ -21,12 +21,13 @@ import ( "aletheiaware.com/bcclientgo" "aletheiaware.com/bcfynego/storage" "aletheiaware.com/bcfynego/ui" - "aletheiaware.com/bcfynego/ui/account" + accountui "aletheiaware.com/bcfynego/ui/account" "aletheiaware.com/bcfynego/ui/data" "aletheiaware.com/bcgo" + "aletheiaware.com/bcgo/account" + "aletheiaware.com/bcgo/node" "aletheiaware.com/cryptogo" "bytes" - "errors" "fmt" "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" @@ -37,80 +38,131 @@ import ( "log" "os" "runtime/debug" + "sync" ) -type BCFyne struct { - App fyne.App - Window fyne.Window - Dialog dialog.Dialog - OnKeysExported func(string) - OnKeysImported func(string) - OnSignedIn func(*bcgo.Node) - OnSignedUp func(*bcgo.Node) - OnSignedOut func() +type BCFyne interface { + App() fyne.App + Window() fyne.Window + AddOnKeysExported(func(string)) + AddOnKeysImported(func(string)) + AddOnSignedIn(func(bcgo.Account)) + AddOnSignedUp(func(bcgo.Account)) + AddOnSignedOut(func()) + DeleteKeys(bcclientgo.BCClient, bcgo.Account) + ExportKeys(bcclientgo.BCClient, bcgo.Account) + Logo() fyne.CanvasObject + Account(bcclientgo.BCClient) (bcgo.Account, error) + Node(bcclientgo.BCClient) (bcgo.Node, error) + ShowAccessDialog(bcclientgo.BCClient, func(bcgo.Account)) + ShowAccount(bcclientgo.BCClient) + ShowError(error) + ShowURI(bcclientgo.BCClient, fyne.URI) + SignOut(bcclientgo.BCClient) } -func NewBCFyne(a fyne.App, w fyne.Window) *BCFyne { - return &BCFyne{ - App: a, - Window: w, +type bcFyne struct { + app fyne.App + window fyne.Window + onKeysExported []func(string) + onKeysImported []func(string) + onSignedIn []func(bcgo.Account) + onSignedUp []func(bcgo.Account) + onSignedOut []func() +} + +func NewBCFyne(a fyne.App, w fyne.Window) BCFyne { + return &bcFyne{ + app: a, + window: w, } } -func (f *BCFyne) ExistingNode(client *bcclientgo.BCClient, alias string, password []byte, callback func(*bcgo.Node)) { - rootDir, err := client.GetRoot() +func (f *bcFyne) App() fyne.App { + return f.app +} + +func (f *bcFyne) Window() fyne.Window { + return f.window +} + +func (f *bcFyne) AddOnKeysExported(callback func(string)) { + f.onKeysExported = append(f.onKeysExported, callback) +} + +func (f *bcFyne) AddOnKeysImported(callback func(string)) { + f.onKeysImported = append(f.onKeysImported, callback) +} + +func (f *bcFyne) AddOnSignedIn(callback func(bcgo.Account)) { + f.onSignedIn = append(f.onSignedIn, callback) +} + +func (f *bcFyne) AddOnSignedUp(callback func(bcgo.Account)) { + f.onSignedUp = append(f.onSignedUp, callback) +} + +func (f *bcFyne) AddOnSignedOut(callback func()) { + f.onSignedOut = append(f.onSignedOut, callback) +} + +func (f *bcFyne) ExistingAccount(client bcclientgo.BCClient, alias string, password []byte, callback func(bcgo.Account)) { + rootDir, err := client.Root() if err != nil { f.ShowError(err) return } // Get key store - keystore, err := bcgo.GetKeyDirectory(rootDir) + keystore, err := bcgo.KeyDirectory(rootDir) if err != nil { f.ShowError(err) return } // Get private key - key, err := cryptogo.GetRSAPrivateKey(keystore, alias, password) + key, err := cryptogo.RSAPrivateKey(keystore, alias, password) if err != nil { f.ShowError(err) return } - cache, err := client.GetCache() - if err != nil { - f.ShowError(err) - return - } - network, err := client.GetNetwork() - if err != nil { - f.ShowError(err) - return - } - // Create node - node := &bcgo.Node{ - Alias: alias, - Key: key, - Cache: cache, - Network: network, - Channels: make(map[string]*bcgo.Channel), - } - + account := account.NewRSA(alias, key) if c := callback; c != nil { - c(node) + c(account) } } -func (f *BCFyne) GetNode(client *bcclientgo.BCClient) (*bcgo.Node, error) { - if client.Node == nil { - nc := make(chan *bcgo.Node, 1) - go f.ShowAccessDialog(client, func(n *bcgo.Node) { - nc <- n +func (f *bcFyne) Account(client bcclientgo.BCClient) (bcgo.Account, error) { + if !client.HasAccount() { + var wg sync.WaitGroup + wg.Add(1) + go f.ShowAccessDialog(client, func(a bcgo.Account) { + client.SetAccount(a) + wg.Done() }) - client.Node = <-nc + wg.Wait() } - return client.Node, nil + return client.Account() } -func (f *BCFyne) GetLogo() fyne.CanvasObject { +func (f *bcFyne) Node(client bcclientgo.BCClient) (bcgo.Node, error) { + if !client.HasNode() { + account, err := f.Account(client) + if err != nil { + return nil, err + } + cache, err := client.Cache() + if err != nil { + return nil, err + } + network, err := client.Network() + if err != nil { + return nil, err + } + client.SetNode(node.New(account, cache, network)) + } + return client.Node() +} + +func (f *bcFyne) Logo() fyne.CanvasObject { return &canvas.Image{ Resource: data.Logo, //FillMode: canvas.ImageFillContain, @@ -118,19 +170,19 @@ func (f *BCFyne) GetLogo() fyne.CanvasObject { } } -func (f *BCFyne) NewNode(client *bcclientgo.BCClient, alias string, password []byte, callback func(*bcgo.Node)) { - // Show progress dialog - progress := dialog.NewProgressInfinite("Creating", "Creating "+alias, f.Window) +func (f *bcFyne) NewAccount(client bcclientgo.BCClient, alias string, password []byte, callback func(bcgo.Account)) { + // Show Progress Dialog + progress := dialog.NewProgressInfinite("Creating", "Creating "+alias, f.window) progress.Show() defer progress.Hide() - rootDir, err := client.GetRoot() + rootDir, err := client.Root() if err != nil { f.ShowError(err) return } // Get key store - keystore, err := bcgo.GetKeyDirectory(rootDir) + keystore, err := bcgo.KeyDirectory(rootDir) if err != nil { f.ShowError(err) return @@ -141,107 +193,109 @@ func (f *BCFyne) NewNode(client *bcclientgo.BCClient, alias string, password []b f.ShowError(err) return } - cache, err := client.GetCache() + account := account.NewRSA(alias, key) + cache, err := client.Cache() if err != nil { f.ShowError(err) return } - network, err := client.GetNetwork() + network, err := client.Network() if err != nil { f.ShowError(err) return } // Create node - node := &bcgo.Node{ - Alias: alias, - Key: key, - Cache: cache, - Network: network, - Channels: make(map[string]*bcgo.Channel), - } + node := node.New(account, cache, network) { // Show Progress Dialog - progress := dialog.NewProgress("Registering", "Registering "+alias, f.Window) + progress := dialog.NewProgress("Registering", "Registering "+alias, f.window) progress.Show() - defer progress.Hide() listener := &ui.ProgressMiningListener{Func: progress.SetValue} // Register Alias - if err := aliasgo.Register(node, listener); err != nil { + err := aliasgo.Register(node, listener) + + // Hide Progress Dialog + progress.Hide() + + if err != nil { f.ShowError(err) return } } if c := callback; c != nil { - c(node) + c(account) } } -func (f *BCFyne) ShowAccessDialog(client *bcclientgo.BCClient, callback func(*bcgo.Node)) { - signIn := account.NewSignIn() - importKey := account.NewImportKey() - signUp := account.NewSignUp() - if d := f.Dialog; d != nil { - d.Hide() - } +func (f *bcFyne) ShowAccessDialog(client bcclientgo.BCClient, callback func(bcgo.Account)) { + signIn := accountui.NewSignIn() + importKey := accountui.NewImportKey() + signUp := accountui.NewSignUp() + accordion := widget.NewAccordion( + &widget.AccordionItem{Title: "Sign In", Detail: signIn.CanvasObject(), Open: true}, + widget.NewAccordionItem("Import Keys", importKey.CanvasObject()), + widget.NewAccordionItem("Sign Up", signUp.CanvasObject()), + ) tos := &widget.Hyperlink{Text: "Terms of Service"} tos.SetURLFromString("https://aletheiaware.com/terms-of-service.html") pp := &widget.Hyperlink{Text: "Privacy Policy", Alignment: fyne.TextAlignTrailing} pp.SetURLFromString("https://aletheiaware.com/privacy-policy.html") - f.Dialog = dialog.NewCustom("Account Access", "Cancel", - container.NewVBox( - widget.NewAccordion( - &widget.AccordionItem{Title: "Sign In", Detail: signIn.CanvasObject(), Open: true}, - widget.NewAccordionItem("Import Keys", importKey.CanvasObject()), - widget.NewAccordionItem("Sign Up", signUp.CanvasObject()), - ), - container.NewGridWithColumns(2, tos, pp), - ), - f.Window) + contents := container.NewVBox() + if !bcgo.IsLive() { + contents.Add(ui.NewTestModeSign()) + } + contents.Add(accordion) + contents.Add(container.NewMax( + &canvas.Image{ + Resource: data.AW, + FillMode: canvas.ImageFillContain, + }, + container.NewGridWithColumns(2, tos, pp), + )) + d := dialog.NewCustom("Account Access", "Cancel", contents, f.window) signInAction := func() { - if d := f.Dialog; d != nil { - d.Hide() - } + d.Hide() + alias := signIn.Alias.Text password := []byte(signIn.Password.Text) if len(password) < cryptogo.MIN_PASSWORD { - f.ShowError(fmt.Errorf(cryptogo.ERROR_PASSWORD_TOO_SHORT, len(password), cryptogo.MIN_PASSWORD)) + f.ShowError(cryptogo.ErrPasswordTooShort{Size: len(password), Min: cryptogo.MIN_PASSWORD}) return } - f.ExistingNode(client, alias, password, func(node *bcgo.Node) { + f.ExistingAccount(client, alias, password, func(account bcgo.Account) { if c := callback; c != nil { - c(node) + c(account) } - if c := f.OnSignedIn; c != nil { - go c(node) + for _, c := range f.onSignedIn { + c(account) } }) } signIn.Alias.OnSubmitted = func(string) { - f.Window.Canvas().Focus(signIn.Password) + f.window.Canvas().Focus(signIn.Password) } signIn.Password.OnSubmitted = func(string) { signInAction() } signIn.SignInButton.OnTapped = signInAction importKeyAction := func() { - if d := f.Dialog; d != nil { - d.Hide() - } + d.Hide() - host := bcgo.GetBCWebsite() + host := bcgo.BCWebsite() alias := importKey.Alias.Text access := importKey.Access.Text // Show Progress Dialog - progress := dialog.NewProgress("Importing Keys", fmt.Sprintf("Importing %s from %s", alias, host), f.Window) + progress := dialog.NewProgress("Importing Keys", fmt.Sprintf("Importing %s from %s", alias, host), f.window) progress.Show() err := client.ImportKeys(host, alias, access) + // Hide Progress Dialog progress.Hide() if err != nil { @@ -249,26 +303,34 @@ func (f *BCFyne) ShowAccessDialog(client *bcclientgo.BCClient, callback func(*bc return } - if c := f.OnKeysImported; c != nil { - go c(alias) + for _, c := range f.onKeysImported { + c(alias) } - authentication := account.NewAuthentication(alias) + authentication := accountui.NewAuthentication(alias) + + contents := container.NewVBox() + if !bcgo.IsLive() { + contents.Add(ui.NewTestModeSign()) + } + contents.Add(widget.NewLabel(fmt.Sprintf("Keys for %s successfully imported from %s.\nAuthenticate to continue", alias, host))) + contents.Add(authentication.CanvasObject()) + d := dialog.NewCustom("Keys Imported", "Cancel", contents, f.window) + authenticateAction := func() { - if d := f.Dialog; d != nil { - d.Hide() - } + d.Hide() + password := []byte(authentication.Password.Text) if len(password) < cryptogo.MIN_PASSWORD { - f.ShowError(fmt.Errorf(cryptogo.ERROR_PASSWORD_TOO_SHORT, len(password), cryptogo.MIN_PASSWORD)) + f.ShowError(cryptogo.ErrPasswordTooShort{Size: len(password), Min: cryptogo.MIN_PASSWORD}) return } - f.ExistingNode(client, alias, password, func(node *bcgo.Node) { + f.ExistingAccount(client, alias, password, func(account bcgo.Account) { if c := callback; c != nil { - c(node) + c(account) } - if c := f.OnSignedIn; c != nil { - go c(node) + for _, c := range f.onSignedIn { + c(account) } }) } @@ -278,24 +340,19 @@ func (f *BCFyne) ShowAccessDialog(client *bcclientgo.BCClient, callback func(*bc authentication.AuthenticateButton.OnTapped = authenticateAction // Show Success Dialog - f.Dialog = dialog.NewCustom("Keys Imported", "Cancel", - container.NewVBox( - widget.NewLabel(fmt.Sprintf("Keys for %s successfully imported from %s.\nAuthenticate to continue", alias, host)), - authentication.CanvasObject()), f.Window) - f.Dialog.Show() - f.Dialog.Resize(ui.DialogSize) + d.Show() + d.Resize(ui.DialogSize) } importKey.Alias.OnSubmitted = func(string) { - f.Window.Canvas().Focus(importKey.Access) + f.window.Canvas().Focus(importKey.Access) } importKey.Access.OnSubmitted = func(string) { importKeyAction() } importKey.ImportKeyButton.OnTapped = importKeyAction signUpAction := func() { - if d := f.Dialog; d != nil { - d.Hide() - } + d.Hide() + alias := signUp.Alias.Text password := []byte(signUp.Password.Text) confirm := []byte(signUp.Confirm.Text) @@ -306,40 +363,52 @@ func (f *BCFyne) ShowAccessDialog(client *bcclientgo.BCClient, callback func(*bc return } + // TODO check Alias is Unique + if len(password) < cryptogo.MIN_PASSWORD { - f.ShowError(fmt.Errorf(cryptogo.ERROR_PASSWORD_TOO_SHORT, len(password), cryptogo.MIN_PASSWORD)) + f.ShowError(cryptogo.ErrPasswordTooShort{Size: len(password), Min: cryptogo.MIN_PASSWORD}) return } if !bytes.Equal(password, confirm) { - f.ShowError(errors.New(cryptogo.ERROR_PASSWORDS_DO_NOT_MATCH)) + f.ShowError(cryptogo.ErrPasswordsDoNotMatch{}) return } - f.NewNode(client, alias, password, func(node *bcgo.Node) { + f.NewAccount(client, alias, password, func(account bcgo.Account) { if c := callback; c != nil { - c(node) + c(account) } - if c := f.OnSignedUp; c != nil { - go c(node) + for _, c := range f.onSignedUp { + c(account) } }) } signUp.Alias.OnSubmitted = func(string) { - f.Window.Canvas().Focus(signUp.Password) + f.window.Canvas().Focus(signUp.Password) } signUp.Password.OnSubmitted = func(string) { - f.Window.Canvas().Focus(signUp.Confirm) + f.window.Canvas().Focus(signUp.Confirm) } signUp.Confirm.OnSubmitted = func(string) { signUpAction() } + signUp.Alias.Validator = func(alias string) error { + if err := aliasgo.ValidateAlias(alias); err != nil { + return err + } + + // TODO check Alias is Unique + + return nil + } + signUp.SignUpButton.OnTapped = signUpAction - rootDir, err := client.GetRoot() + rootDir, err := client.Root() if err != nil { log.Println(err) } else { - keystore, err := bcgo.GetKeyDirectory(rootDir) + keystore, err := bcgo.KeyDirectory(rootDir) if err != nil { log.Println(err) } else { @@ -365,58 +434,62 @@ func (f *BCFyne) ShowAccessDialog(client *bcclientgo.BCClient, callback func(*bc signIn.Password.SetText(pwd) } - f.Dialog.Show() - f.Dialog.Resize(ui.DialogSize) + if signIn.Alias.Text == "" { + // Make accordion show sign up as open instead of sign in + accordion.Open(2) + } + + // Show Access Dialog + d.Show() + d.Resize(ui.DialogSize) } -func (f *BCFyne) ShowAccount(client *bcclientgo.BCClient) { - node, err := f.GetNode(client) +func (f *bcFyne) ShowAccount(client bcclientgo.BCClient) { + account, err := f.Account(client) if err != nil { f.ShowError(err) return } - form, err := nodeView(node) + form, err := identityView(account) if err != nil { f.ShowError(err) return } - box := container.NewVBox( - form, - ) - if d := f.Dialog; d != nil { - d.Hide() + contents := container.NewVBox() + if !bcgo.IsLive() { + contents.Add(ui.NewTestModeSign()) } - f.Dialog = dialog.NewCustom("Account", "OK", box, f.Window) - box.Add(widget.NewButton("Export Keys", func() { - f.ExportKeys(client, node) + contents.Add(form) + + d := dialog.NewCustom("Account", "OK", contents, f.window) + contents.Add(widget.NewButton("Export Keys", func() { + f.ExportKeys(client, account) })) - box.Add(widget.NewButton("Delete Keys", func() { - f.Dialog.Hide() - f.DeleteKeys(client, node) + contents.Add(widget.NewButton("Delete Keys", func() { + d.Hide() + f.DeleteKeys(client, account) })) - box.Add(widget.NewButton("Sign Out", func() { - f.Dialog.Hide() + contents.Add(widget.NewButton("Sign Out", func() { + d.Hide() f.SignOut(client) })) - f.Dialog.Show() - f.Dialog.Resize(ui.DialogSize) + d.Show() + d.Resize(ui.DialogSize) } -func (f *BCFyne) DeleteKeys(client *bcclientgo.BCClient, node *bcgo.Node) { +func (f *bcFyne) DeleteKeys(client bcclientgo.BCClient, account bcgo.Account) { f.ShowError(fmt.Errorf("Not yet implemented: %s", "BCFyne.DeleteKeys")) } -func (f *BCFyne) ExportKeys(client *bcclientgo.BCClient, node *bcgo.Node) { - authentication := account.NewAuthentication(node.Alias) +func (f *bcFyne) ExportKeys(client bcclientgo.BCClient, account bcgo.Account) { + alias := account.Alias() + authentication := accountui.NewAuthentication(alias) authenticateAction := func() { - if d := f.Dialog; d != nil { - d.Hide() - } - host := bcgo.GetBCWebsite() + host := bcgo.BCWebsite() // Show Progress Dialog - progress := dialog.NewProgress("Exporting Keys", fmt.Sprintf("Exporting %s to %s", node.Alias, host), f.Window) + progress := dialog.NewProgress("Exporting Keys", fmt.Sprintf("Exporting %s to %s", alias, host), f.window) progress.Show() var ( @@ -426,11 +499,12 @@ func (f *BCFyne) ExportKeys(client *bcclientgo.BCClient, node *bcgo.Node) { password := []byte(authentication.Password.Text) if len(password) < cryptogo.MIN_PASSWORD { - err = fmt.Errorf(cryptogo.ERROR_PASSWORD_TOO_SHORT, len(password), cryptogo.MIN_PASSWORD) + err = cryptogo.ErrPasswordTooShort{Size: len(password), Min: cryptogo.MIN_PASSWORD} } else { - access, err = client.ExportKeys(host, node.Alias, password) + access, err = client.ExportKeys(host, alias, password) } + // Hide Progress Dialog progress.Hide() if err != nil { @@ -439,53 +513,61 @@ func (f *BCFyne) ExportKeys(client *bcclientgo.BCClient, node *bcgo.Node) { } form := widget.NewForm( - widget.NewFormItem("Alias", widget.NewLabel(node.Alias)), + widget.NewFormItem("Alias", widget.NewLabel(alias)), widget.NewFormItem("Access Code", container.NewHBox( widget.NewLabel(access), widget.NewButtonWithIcon("", theme.ContentCopyIcon(), func() { - f.Window.Clipboard().SetContent(access) - dialog.ShowInformation("Copied", "Access code copied to clipboard", f.Window) + f.window.Clipboard().SetContent(access) + dialog.ShowInformation("Copied", "Access code copied to clipboard", f.window) }), )), ) - f.Dialog = dialog.NewCustom("Keys Exported", "OK", form, f.Window) - f.Dialog.Show() - f.Dialog.Resize(ui.DialogSize) + contents := container.NewVBox() + if !bcgo.IsLive() { + contents.Add(ui.NewTestModeSign()) + } + contents.Add(form) + d := dialog.NewCustom("Keys Exported", "OK", contents, f.window) + d.Show() + d.Resize(ui.DialogSize) - if c := f.OnKeysExported; c != nil { - go c(node.Alias) + for _, c := range f.onKeysExported { + c(alias) } } authentication.Password.OnSubmitted = func(string) { authenticateAction() } authentication.AuthenticateButton.OnTapped = authenticateAction - f.Dialog = dialog.NewCustom("Account", "Cancel", authentication.CanvasObject(), f.Window) - f.Dialog.Show() - f.Dialog.Resize(ui.DialogSize) + + contents := container.NewVBox() + if !bcgo.IsLive() { + contents.Add(ui.NewTestModeSign()) + } + contents.Add(authentication.CanvasObject()) + d := dialog.NewCustom("Account", "Cancel", contents, f.window) + d.Show() + d.Resize(ui.DialogSize) } -func (f *BCFyne) SignOut(client *bcclientgo.BCClient) { - client.Root = "" - client.Cache = nil - client.Network = nil - client.Node = nil - if c := f.OnSignedOut; c != nil { - go c() +func (f *bcFyne) SignOut(client bcclientgo.BCClient) { + client.SetRoot("") + client.SetCache(nil) + client.SetNetwork(nil) + client.SetAccount(nil) + client.SetNode(nil) + for _, c := range f.onSignedOut { + c() } } -func (f *BCFyne) ShowError(err error) { +func (f *bcFyne) ShowError(err error) { log.Println("Error:", err) debug.PrintStack() - if d := f.Dialog; d != nil { - d.Hide() - } - f.Dialog = dialog.NewError(err, f.Window) - f.Dialog.Show() + dialog.ShowError(err, f.window) } -func (f *BCFyne) ShowURI(client *bcclientgo.BCClient, uri fyne.URI) { +func (f *bcFyne) ShowURI(client bcclientgo.BCClient, uri fyne.URI) { var view fyne.CanvasObject switch u := uri.(type) { case storage.AliasURI: @@ -509,35 +591,37 @@ func (f *BCFyne) ShowURI(client *bcclientgo.BCClient, uri fyne.URI) { return } - window := f.App.NewWindow(uri.Name()) + window := f.app.NewWindow(uri.Name()) window.SetContent(container.NewVScroll(view)) window.Resize(ui.WindowSize) window.CenterOnScreen() window.Show() } -func (f *BCFyne) ShowNode(node *bcgo.Node) { - form, err := nodeView(node) +func (f *bcFyne) ShowIdentity(identity bcgo.Identity) { + form, err := identityView(identity) if err != nil { f.ShowError(err) return } - if d := f.Dialog; d != nil { - d.Hide() + contents := container.NewVBox() + if !bcgo.IsLive() { + contents.Add(ui.NewTestModeSign()) } - f.Dialog = dialog.NewCustom("Node", "OK", form, f.Window) - f.Dialog.Show() + contents.Add(form) + dialog.ShowCustom("Identity", "OK", contents, f.window) } -func nodeView(node *bcgo.Node) (fyne.CanvasObject, error) { - publicKeyBytes, err := cryptogo.RSAPublicKeyToPKIXBytes(&node.Key.PublicKey) +func identityView(identity bcgo.Identity) (fyne.CanvasObject, error) { + format, bytes, err := identity.PublicKey() if err != nil { return nil, err } - aliasScroller := container.NewHScroll(ui.NewAliasLabel(node.Alias)) - publicKeyScroller := container.NewVScroll(ui.NewKeyLabel(publicKeyBytes)) - publicKeyScroller.SetMinSize(fyne.NewSize(0, 10*theme.TextSize())) // Show at least 10 lines + aliasScroller := container.NewHScroll(ui.NewAliasLabel(identity.Alias())) + bytesScroller := container.NewVScroll(ui.NewKeyLabel(bytes)) + bytesScroller.SetMinSize(fyne.NewSize(0, 10*theme.TextSize())) // Show at least 10 lines + formatScroller := container.NewVScroll(widget.NewLabel(format.String())) return widget.NewForm( widget.NewFormItem( @@ -546,7 +630,11 @@ func nodeView(node *bcgo.Node) (fyne.CanvasObject, error) { ), widget.NewFormItem( "Public Key", - publicKeyScroller, + bytesScroller, + ), + widget.NewFormItem( + "Public Key Format", + formatScroller, ), ), nil } diff --git a/vendor/aletheiaware.com/bcfynego/go.mod b/vendor/aletheiaware.com/bcfynego/go.mod index 8552873..2113cbe 100644 --- a/vendor/aletheiaware.com/bcfynego/go.mod +++ b/vendor/aletheiaware.com/bcfynego/go.mod @@ -3,9 +3,9 @@ module aletheiaware.com/bcfynego go 1.14 require ( - aletheiaware.com/aliasgo v1.1.3 - aletheiaware.com/bcclientgo v1.1.4 - aletheiaware.com/bcgo v1.1.4 - aletheiaware.com/cryptogo v1.1.1 - fyne.io/fyne/v2 v2.0.0 + aletheiaware.com/aliasgo v1.2.3 + aletheiaware.com/bcclientgo v1.2.3 + aletheiaware.com/bcgo v1.2.3 + aletheiaware.com/cryptogo v1.2.2 + fyne.io/fyne/v2 v2.0.2 ) diff --git a/vendor/aletheiaware.com/bcfynego/go.sum b/vendor/aletheiaware.com/bcfynego/go.sum index 62b6732..4e039df 100644 --- a/vendor/aletheiaware.com/bcfynego/go.sum +++ b/vendor/aletheiaware.com/bcfynego/go.sum @@ -1,15 +1,15 @@ -aletheiaware.com/aliasgo v1.1.3 h1:RnJhpWcbH7KWWWgIvUCVS+++mzpjYNk/dQm4o1G0lX8= -aletheiaware.com/aliasgo v1.1.3/go.mod h1:JY9/j4q6ZniHb0vKO7CJJ3M03eTVhczoIIhJBZ6Sa3w= -aletheiaware.com/bcclientgo v1.1.4 h1:mSdMxH3gNDYHOwfJTwVeQwxzJsZ5Trh8Wf5K1SG4IKM= -aletheiaware.com/bcclientgo v1.1.4/go.mod h1:Ra5xSJ6fPdlcEQR4bL9wVY6PiFmlfgHl8Z0U5k3GP8Y= -aletheiaware.com/bcgo v1.1.4 h1:HuAk12UeOvtIXlc7WN2XIj9tV+jNA5uCi+D8Z0V2twU= -aletheiaware.com/bcgo v1.1.4/go.mod h1:GXvFFZ8JrATGrvuKA0J3ucf9+91eC94ggphNVpg3XUM= -aletheiaware.com/cryptogo v1.1.1 h1:XrzGXcTgYQbuL3tQv/idVzAIblb2k+o77iigiQiXTUQ= -aletheiaware.com/cryptogo v1.1.1/go.mod h1:sT8jDe5zWSIswZDAilLwfX2N6l4WOFQBm+4lYxx1Ae0= -aletheiaware.com/testinggo v1.1.2 h1:/zCBvslySEY4uJ2qnnyvhFdgIERa/jzlgHBOmS4lL1k= -aletheiaware.com/testinggo v1.1.2/go.mod h1:bqmrqRyMkGbTa9E/1D8xHE0KLmOw+HRG0skc/XwrdcY= -fyne.io/fyne/v2 v2.0.0 h1:TfsS3bNq5663BpXsoz1OfzyjcaMqqOf9usI8ZKkw4IE= -fyne.io/fyne/v2 v2.0.0/go.mod h1:FmobqvPpBW+nG1nDyxZWf1SQLED9g/vXIxiIIVjHazY= +aletheiaware.com/aliasgo v1.2.3 h1:joMErbHdyo+jVbIoA9HWMPmUVfhZjabBVaB5AnYYObQ= +aletheiaware.com/aliasgo v1.2.3/go.mod h1:wSp0m2ZOXA3M3ZKFcUtcf2ANBio5JSXxQx07IpxwaGM= +aletheiaware.com/bcclientgo v1.2.3 h1:bkUjPmDCQIajTHEKveziyxq/StvBCCoOfSmwxfTqobg= +aletheiaware.com/bcclientgo v1.2.3/go.mod h1:ZUl59XyDsLGYqumzo2woBKhqVv9zjgoa/UQqFF8NPV4= +aletheiaware.com/bcgo v1.2.3 h1:5vRjjrkmlSh0/cwhY5u+0S4RUpvTCAMN1HVJMBl9A88= +aletheiaware.com/bcgo v1.2.3/go.mod h1:zNPBDrox6aUVv8ns5UOzcaDXzD/p5tZ0lGSxlfT6/Rs= +aletheiaware.com/cryptogo v1.2.2 h1:d7vEEgf3bZFnLk+HG1wCAY/pgRz+zNYvKFpxsli3Mng= +aletheiaware.com/cryptogo v1.2.2/go.mod h1:B1mJVIsfEDJoovkD2fLsZXgXxR1AAe2cDmjFwt7Eau4= +aletheiaware.com/testinggo v1.2.2 h1:w+ir8ehcnIcZ+jTjalGWAkh3So9PaJm5g3CPgLnPtXE= +aletheiaware.com/testinggo v1.2.2/go.mod h1:TijVTRIGnue9UHlxT9YgLp5VGWOo4PI9VRflCm4v4xo= +fyne.io/fyne/v2 v2.0.2 h1:6pDvFuCmL1odyT/fPI+2L54hMJW1Zt9Dno41HmLInRs= +fyne.io/fyne/v2 v2.0.2/go.mod h1:3+FYmLJVgeb8EvTPJ5YzZeo7LkAq4bbuY3Zrir6xHbg= github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9 h1:1ltqoej5GtaWF8jaiA49HwsZD459jqm9YFz9ZtMFpQA= github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I= github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw= @@ -22,27 +22,21 @@ github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8 github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fyne-io/mobile v0.1.2 h1:0HaXDtOOwyOTn3Umi0uKVCOgJtfX73c6unC4U8i5VZU= -github.com/fyne-io/mobile v0.1.2/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY= +github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f h1:rguJ/t99j/6zRSFzsBKlsmmyl+vOvCeTJ+2uTBvuXFI= +github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY= github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw= github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3 h1:q521PfSp5/z6/sD9FZZOWj4d1MLmfQW8PkRnI9M6PCE= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48 h1:QrUfZrT8n72FUuiABt4tbu8PwDnOPAbnj3Mql1UhdRI= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8= github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw= -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.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526 h1:NfuKjkj/Xc2z1xZIj+EmNCm5p1nKJPyw3F4E20usXvg= github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc= github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca h1:ozPUX9TKQZVek4lZWYRsQo7uS8vJ+q4OOHvRhHiCLfU= @@ -71,11 +65,13 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.1.25/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-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc h1:+q90ECDSAQirdykUN6sPEiBXBsp8Csjcca8Oy7bgLTA= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw= @@ -88,21 +84,26 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666 h1:gVCS+QOncANNPlmlO1AhlU3oxs4V9z+gTtPwIk3p2N8= golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -112,16 +113,14 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/aletheiaware.com/bcfynego/storage/repository.go b/vendor/aletheiaware.com/bcfynego/storage/repository.go index 6110226..772f244 100644 --- a/vendor/aletheiaware.com/bcfynego/storage/repository.go +++ b/vendor/aletheiaware.com/bcfynego/storage/repository.go @@ -40,76 +40,76 @@ type BCRepository interface { Register() } -type bcrepo struct { - client *bcclientgo.BCClient +type bcRepository struct { + client bcclientgo.BCClient } -func NewBCRepository(client *bcclientgo.BCClient) BCRepository { - return &bcrepo{ +func NewBCRepository(client bcclientgo.BCClient) BCRepository { + return &bcRepository{ client: client, } } -func (r *bcrepo) CanList(u fyne.URI) (bool, error) { +func (r *bcRepository) CanList(u fyne.URI) (bool, error) { // TODO return false, fmt.Errorf("%s: Not Yet Implemented", "BCRepository.CanList") } -func (r *bcrepo) CanRead(u fyne.URI) (bool, error) { +func (r *bcRepository) CanRead(u fyne.URI) (bool, error) { // TODO return false, fmt.Errorf("%s: Not Yet Implemented", "BCRepository.CanRead") } -func (r *bcrepo) CanWrite(u fyne.URI) (bool, error) { +func (r *bcRepository) CanWrite(u fyne.URI) (bool, error) { // TODO return false, fmt.Errorf("%s: Not Yet Implemented", "BCRepository.CanWrite") } -func (r *bcrepo) Child(fyne.URI, string) (fyne.URI, error) { +func (r *bcRepository) Child(fyne.URI, string) (fyne.URI, error) { // TODO return nil, fmt.Errorf("%s: Not Yet Implemented", "BCRepository.Child") } -func (r *bcrepo) Copy(fyne.URI, fyne.URI) error { +func (r *bcRepository) Copy(fyne.URI, fyne.URI) error { // TODO return fmt.Errorf("%s: Not Yet Implemented", "BCRepository.Copy") } -func (r *bcrepo) CreateListable(u fyne.URI) error { +func (r *bcRepository) CreateListable(u fyne.URI) error { // TODO return fmt.Errorf("%s: Not Yet Implemented", "BCRepository.CreateListable") } -func (r *bcrepo) Delete(u fyne.URI) error { +func (r *bcRepository) Delete(u fyne.URI) error { // BC is indelible return repository.ErrOperationNotSupported } -func (r *bcrepo) Destroy(string) { +func (r *bcRepository) Destroy(string) { // Do nothing } -func (r *bcrepo) Exists(u fyne.URI) (bool, error) { +func (r *bcRepository) Exists(u fyne.URI) (bool, error) { // TODO return false, fmt.Errorf("%s: Not Yet Implemented", "BCRepository.Exists") } -func (r *bcrepo) List(u fyne.URI) ([]fyne.URI, error) { +func (r *bcRepository) List(u fyne.URI) ([]fyne.URI, error) { // TODO return nil, fmt.Errorf("%s: Not Yet Implemented", "BCRepository.List") } -func (r *bcrepo) Move(fyne.URI, fyne.URI) error { +func (r *bcRepository) Move(fyne.URI, fyne.URI) error { // BC is immutable return repository.ErrOperationNotSupported } -func (r *bcrepo) Parent(fyne.URI) (fyne.URI, error) { +func (r *bcRepository) Parent(fyne.URI) (fyne.URI, error) { // TODO return nil, fmt.Errorf("%s: Not Yet Implemented", "BCRepository.Parent") } -func (r *bcrepo) ParseURI(s string) (fyne.URI, error) { +func (r *bcRepository) ParseURI(s string) (fyne.URI, error) { if strings.HasPrefix(s, ALIAS_SCHEME_PREFIX) { return NewAliasURI(strings.TrimPrefix(s, ALIAS_SCHEME_PREFIX)), nil } @@ -149,16 +149,16 @@ func (r *bcrepo) ParseURI(s string) (fyne.URI, error) { return NewChannelURI(channel), nil } -func (r *bcrepo) Reader(u fyne.URI) (fyne.URIReadCloser, error) { +func (r *bcRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { // TODO return nil, fmt.Errorf("%s: Not Yet Implemented", "BCRepository.Reader") } -func (r *bcrepo) Register() { +func (r *bcRepository) Register() { repository.Register(BC_SCHEME, r) } -func (r *bcrepo) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { +func (r *bcRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { // TODO return nil, fmt.Errorf("%s: Not Yet Implemented", "BCRepository.Writer") } diff --git a/vendor/aletheiaware.com/bcfynego/ui/access.go b/vendor/aletheiaware.com/bcfynego/ui/access.go index 604de96..13755aa 100644 --- a/vendor/aletheiaware.com/bcfynego/ui/access.go +++ b/vendor/aletheiaware.com/bcfynego/ui/access.go @@ -28,13 +28,13 @@ import ( type AccessView struct { widget.Form ui UI - client *bcclientgo.BCClient + client bcclientgo.BCClient alias *Link secretKey *widget.Label encryptionAlgorithm *widget.Label } -func NewAccessView(ui UI, client *bcclientgo.BCClient) *AccessView { +func NewAccessView(ui UI, client bcclientgo.BCClient) *AccessView { v := &AccessView{ ui: ui, client: client, diff --git a/vendor/aletheiaware.com/bcfynego/ui/alias.go b/vendor/aletheiaware.com/bcfynego/ui/alias.go index 7689dee..00ee88e 100644 --- a/vendor/aletheiaware.com/bcfynego/ui/alias.go +++ b/vendor/aletheiaware.com/bcfynego/ui/alias.go @@ -48,13 +48,13 @@ func (a *AliasLabel) SetAlias(alias string) { type AliasView struct { widget.Form ui UI - client *bcclientgo.BCClient + client bcclientgo.BCClient timestamp *TimestampLabel alias *AliasLabel key *KeyLabel } -func NewAliasView(ui UI, client *bcclientgo.BCClient) *AliasView { +func NewAliasView(ui UI, client bcclientgo.BCClient) *AliasView { v := &AliasView{ ui: ui, client: client, @@ -73,11 +73,11 @@ func NewAliasView(ui UI, client *bcclientgo.BCClient) *AliasView { } func (v *AliasView) SetURI(uri storage.AliasURI) error { - cache, err := v.client.GetCache() + cache, err := v.client.Cache() if err != nil { return err } - network, err := v.client.GetNetwork() + network, err := v.client.Network() if err != nil { return err } @@ -86,7 +86,7 @@ func (v *AliasView) SetURI(uri storage.AliasURI) error { // Ignored } alias := uri.Alias() - r, a, err := aliasgo.GetRecord(aliases, cache, network, alias) + r, a, err := aliasgo.Record(aliases, cache, network, alias) if err != nil { return err } diff --git a/vendor/aletheiaware.com/bcfynego/ui/block.go b/vendor/aletheiaware.com/bcfynego/ui/block.go index 6e790e0..6282c54 100644 --- a/vendor/aletheiaware.com/bcfynego/ui/block.go +++ b/vendor/aletheiaware.com/bcfynego/ui/block.go @@ -30,7 +30,7 @@ import ( type BlockView struct { widget.Form ui UI - client *bcclientgo.BCClient + client bcclientgo.BCClient hash *widget.Label timestamp *TimestampLabel channel *Link @@ -41,7 +41,7 @@ type BlockView struct { record *fyne.Container } -func NewBlockView(ui UI, client *bcclientgo.BCClient) *BlockView { +func NewBlockView(ui UI, client bcclientgo.BCClient) *BlockView { v := &BlockView{ ui: ui, client: client, @@ -110,17 +110,17 @@ func NewBlockView(ui UI, client *bcclientgo.BCClient) *BlockView { } func (v *BlockView) SetURI(uri storage.BlockURI) error { - cache, err := v.client.GetCache() + cache, err := v.client.Cache() if err != nil { return err } - network, err := v.client.GetNetwork() + network, err := v.client.Network() if err != nil { return err } name := uri.Channel() hash := uri.BlockHash() - block, err := bcgo.GetBlock(name, cache, network, hash) + block, err := bcgo.LoadBlock(name, cache, network, hash) if err != nil { return err } diff --git a/vendor/aletheiaware.com/bcfynego/ui/data/aw.svg b/vendor/aletheiaware.com/bcfynego/ui/data/aw.svg new file mode 100644 index 0000000..ae6014e --- /dev/null +++ b/vendor/aletheiaware.com/bcfynego/ui/data/aw.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/vendor/aletheiaware.com/bcfynego/ui/data/gen.sh b/vendor/aletheiaware.com/bcfynego/ui/data/gen.sh index 8ec182e..7378a0c 100644 --- a/vendor/aletheiaware.com/bcfynego/ui/data/gen.sh +++ b/vendor/aletheiaware.com/bcfynego/ui/data/gen.sh @@ -17,5 +17,6 @@ set -e set -x -fyne bundle -name Logo -package data bc.svg > icon.go +fyne bundle -name AW -package data aw.svg > icon.go +fyne bundle -append -name Logo -package data bc.svg >> icon.go fyne bundle -append -name AccountIcon -package data account.svg >> icon.go diff --git a/vendor/aletheiaware.com/bcfynego/ui/data/icon.go b/vendor/aletheiaware.com/bcfynego/ui/data/icon.go index b8ea0c5..703eb57 100644 --- a/vendor/aletheiaware.com/bcfynego/ui/data/icon.go +++ b/vendor/aletheiaware.com/bcfynego/ui/data/icon.go @@ -5,11 +5,18 @@ package data import "fyne.io/fyne/v2" +var AW = &fyne.StaticResource{ + StaticName: "aw.svg", + StaticContent: []byte( + "\n\n \n \n \n \n\n"), +} var Logo = &fyne.StaticResource{ - StaticName: "bc.svg", - StaticContent: []byte("\n\n \n \n \n \n \n \n \n \n \n \n \n\n"), + StaticName: "bc.svg", + StaticContent: []byte( + "\n\n \n \n \n \n \n \n \n \n \n \n \n\n"), } var AccountIcon = &fyne.StaticResource{ - StaticName: "account.svg", - StaticContent: []byte("\n\n \n\n"), + StaticName: "account.svg", + StaticContent: []byte( + "\n\n \n\n"), } diff --git a/vendor/aletheiaware.com/bcfynego/ui/head.go b/vendor/aletheiaware.com/bcfynego/ui/head.go index 1a86e4d..9bff357 100644 --- a/vendor/aletheiaware.com/bcfynego/ui/head.go +++ b/vendor/aletheiaware.com/bcfynego/ui/head.go @@ -20,6 +20,7 @@ import ( "aletheiaware.com/bcclientgo" "aletheiaware.com/bcfynego/storage" "aletheiaware.com/bcgo" + "aletheiaware.com/bcgo/channel" "encoding/base64" "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" @@ -30,13 +31,13 @@ import ( type HeadView struct { widget.Form ui UI - client *bcclientgo.BCClient + client bcclientgo.BCClient channel *widget.Label hash *Link timestamp *widget.Label } -func NewHeadView(ui UI, client *bcclientgo.BCClient) *HeadView { +func NewHeadView(ui UI, client bcclientgo.BCClient) *HeadView { v := &HeadView{ ui: ui, client: client, @@ -70,34 +71,34 @@ func NewHeadView(ui UI, client *bcclientgo.BCClient) *HeadView { v.Append("Timestamp", v.timestamp) v.Append("", container.NewGridWithColumns(2, widget.NewButton("Pull", func() { - cache, err := v.client.GetCache() + cache, err := v.client.Cache() if err != nil { v.ui.ShowError(err) return } - network, err := v.client.GetNetwork() + network, err := v.client.Network() if err != nil { v.ui.ShowError(err) return } - channel := bcgo.NewChannel(v.channel.Text) + channel := channel.New(v.channel.Text) if err := channel.Pull(cache, network); err != nil { v.ui.ShowError(err) return } }), widget.NewButton("Push", func() { - cache, err := v.client.GetCache() + cache, err := v.client.Cache() if err != nil { v.ui.ShowError(err) return } - network, err := v.client.GetNetwork() + network, err := v.client.Network() if err != nil { v.ui.ShowError(err) return } - channel := bcgo.NewChannel(v.channel.Text) + channel := channel.New(v.channel.Text) if err := channel.Push(cache, network); err != nil { v.ui.ShowError(err) return @@ -114,26 +115,26 @@ func NewHeadView(ui UI, client *bcclientgo.BCClient) *HeadView { } func (v *HeadView) SetURI(uri storage.ChannelURI) error { - cache, err := v.client.GetCache() + cache, err := v.client.Cache() if err != nil { return err } - network, err := v.client.GetNetwork() + network, err := v.client.Network() if err != nil { return err } name := uri.Channel() - channel := bcgo.NewChannel(name) + channel := channel.New(name) if err := channel.Refresh(cache, network); err != nil { // Ignored } - v.hash.SetText(base64.RawURLEncoding.EncodeToString(channel.Head)) + v.hash.SetText(base64.RawURLEncoding.EncodeToString(channel.Head())) v.hash.OnTapped = func() { - v.ui.ShowURI(v.client, storage.NewBlockURI(name, channel.Head)) + v.ui.ShowURI(v.client, storage.NewBlockURI(name, channel.Head())) } v.channel.SetText(name) - v.timestamp.SetText(bcgo.TimestampToString(channel.Timestamp)) + v.timestamp.SetText(bcgo.TimestampToString(channel.Timestamp())) v.Refresh() return nil } diff --git a/vendor/aletheiaware.com/bcfynego/ui/progress.go b/vendor/aletheiaware.com/bcfynego/ui/progress.go index 352a851..4690bde 100644 --- a/vendor/aletheiaware.com/bcfynego/ui/progress.go +++ b/vendor/aletheiaware.com/bcfynego/ui/progress.go @@ -22,14 +22,14 @@ type ProgressMiningListener struct { Func func(f float64) } -func (p *ProgressMiningListener) OnMiningStarted(channel *bcgo.Channel, size uint64) { +func (p *ProgressMiningListener) OnMiningStarted(channel bcgo.Channel, size uint64) { p.Func(0.0) } -func (p *ProgressMiningListener) OnNewMaxOnes(channel *bcgo.Channel, nonce, ones uint64) { +func (p *ProgressMiningListener) OnNewMaxOnes(channel bcgo.Channel, nonce, ones uint64) { p.Func(float64(ones) / 512.0) } -func (p *ProgressMiningListener) OnMiningThresholdReached(channel *bcgo.Channel, hash []byte, block *bcgo.Block) { +func (p *ProgressMiningListener) OnMiningThresholdReached(channel bcgo.Channel, hash []byte, block *bcgo.Block) { p.Func(1.0) } diff --git a/vendor/aletheiaware.com/bcfynego/ui/record.go b/vendor/aletheiaware.com/bcfynego/ui/record.go index 99dfd74..eedcd3c 100644 --- a/vendor/aletheiaware.com/bcfynego/ui/record.go +++ b/vendor/aletheiaware.com/bcfynego/ui/record.go @@ -31,7 +31,7 @@ import ( type RecordView struct { widget.Form ui UI - client *bcclientgo.BCClient + client bcclientgo.BCClient hash *widget.Label timestamp *TimestampLabel creator *Link @@ -45,7 +45,7 @@ type RecordView struct { meta *fyne.Container } -func NewRecordView(ui UI, client *bcclientgo.BCClient) *RecordView { +func NewRecordView(ui UI, client bcclientgo.BCClient) *RecordView { v := &RecordView{ ui: ui, client: client, @@ -123,7 +123,7 @@ func NewRecordView(ui UI, client *bcclientgo.BCClient) *RecordView { func (v *RecordView) SetURI(uri storage.RecordURI) error { name := uri.Channel() - node, err := v.client.GetNode() + node, err := v.client.Node() if err != nil { return err } @@ -131,9 +131,9 @@ func (v *RecordView) SetURI(uri storage.RecordURI) error { recordHash := uri.RecordHash() var block *bcgo.Block if blockHash == nil || len(blockHash) == 0 { - block, err = bcgo.GetBlockContainingRecord(name, node.Cache, node.Network, recordHash) + block, err = bcgo.LoadBlockContainingRecord(name, node.Cache(), node.Network(), recordHash) } else { - block, err = bcgo.GetBlock(name, node.Cache, node.Network, blockHash) + block, err = bcgo.LoadBlock(name, node.Cache(), node.Network(), blockHash) } if err != nil { return err diff --git a/vendor/aletheiaware.com/bcfynego/ui/reference.go b/vendor/aletheiaware.com/bcfynego/ui/reference.go index ee7636f..6256b15 100644 --- a/vendor/aletheiaware.com/bcfynego/ui/reference.go +++ b/vendor/aletheiaware.com/bcfynego/ui/reference.go @@ -29,7 +29,7 @@ import ( type ReferenceView struct { widget.Form ui UI - client *bcclientgo.BCClient + client bcclientgo.BCClient timestamp *TimestampLabel channel *Link block *Link @@ -37,7 +37,7 @@ type ReferenceView struct { index *widget.Label } -func NewReferenceView(ui UI, client *bcclientgo.BCClient) *ReferenceView { +func NewReferenceView(ui UI, client bcclientgo.BCClient) *ReferenceView { v := &ReferenceView{ ui: ui, client: client, diff --git a/vendor/aletheiaware.com/bcfynego/ui/test.go b/vendor/aletheiaware.com/bcfynego/ui/test.go new file mode 100644 index 0000000..123b39d --- /dev/null +++ b/vendor/aletheiaware.com/bcfynego/ui/test.go @@ -0,0 +1,37 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ui + +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/theme" +) + +func NewTestModeSign() fyne.CanvasObject { + return container.NewPadded(&canvas.Text{ + Alignment: fyne.TextAlignCenter, + Color: theme.PrimaryColorNamed(theme.ColorRed), + Text: "TEST MODE", + TextSize: theme.TextSize(), + TextStyle: fyne.TextStyle{ + Bold: true, + Monospace: true, + }, + }) +} diff --git a/vendor/aletheiaware.com/bcfynego/ui/ui.go b/vendor/aletheiaware.com/bcfynego/ui/ui.go index d81c64b..435e2f9 100644 --- a/vendor/aletheiaware.com/bcfynego/ui/ui.go +++ b/vendor/aletheiaware.com/bcfynego/ui/ui.go @@ -29,7 +29,7 @@ var ( type UI interface { ShowError(error) - ShowURI(*bcclientgo.BCClient, fyne.URI) + ShowURI(bcclientgo.BCClient, fyne.URI) } func ShortcutFocused(s fyne.Shortcut, w fyne.Window) { diff --git a/vendor/aletheiaware.com/bcgo/account.go b/vendor/aletheiaware.com/bcgo/account.go new file mode 100644 index 0000000..0141e8e --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/account.go @@ -0,0 +1,34 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bcgo + +import "aletheiaware.com/cryptogo" + +type Account interface { + Identity + // Decrypt takes an Encryption Algorithm, Encrypted Payload, and Symmetric Key. + // The Key is used to decrypt the Payload. + // Decrypt returns the Decrypted Payload, or an error. + Decrypt(cryptogo.EncryptionAlgorithm, []byte, []byte) ([]byte, error) + // DecryptKey takes an Encrytion Algorithm and Encrypted Key. + // The Key is decrypted with this Account's Private Key. + // DecryptKey returns the Decrypted Key, or an error + DecryptKey(cryptogo.EncryptionAlgorithm, []byte) ([]byte, error) + // Sign takes a Payload. + // Sign returns the Signature, Algorithm, or an error. + Sign([]byte) (cryptogo.SignatureAlgorithm, []byte, error) +} diff --git a/vendor/aletheiaware.com/bcgo/account/rsa.go b/vendor/aletheiaware.com/bcgo/account/rsa.go new file mode 100644 index 0000000..b013398 --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/account/rsa.go @@ -0,0 +1,86 @@ +/* + * Copyright 2019-21 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package account + +import ( + "aletheiaware.com/bcgo" + "aletheiaware.com/bcgo/identity" + "aletheiaware.com/cryptogo" + "crypto/rand" + "crypto/rsa" +) + +type rsaAccount struct { + bcgo.Identity + key *rsa.PrivateKey +} + +func GenerateRSA(alias string) (bcgo.Account, error) { + key, err := rsa.GenerateKey(rand.Reader, 4096) + if err != nil { + return nil, err + } + return NewRSA(alias, key), nil +} + +func LoadRSA(directory string) (bcgo.Account, error) { + // Get alias + alias, err := bcgo.Alias() + if err != nil { + return nil, err + } + keystore, err := bcgo.KeyDirectory(directory) + if err != nil { + return nil, err + } + // Get private key + key, err := cryptogo.LoadRSAPrivateKey(keystore, alias) + if err != nil { + return nil, err + } + return NewRSA(alias, key), nil +} + +func NewRSA(alias string, key *rsa.PrivateKey) bcgo.Account { + return &rsaAccount{ + Identity: identity.NewRSA(alias, &key.PublicKey), + key: key, + } +} + +func (a *rsaAccount) Decrypt(algorithm cryptogo.EncryptionAlgorithm, payload, key []byte) ([]byte, error) { + return cryptogo.DecryptPayload(algorithm, payload, key) +} + +func (a *rsaAccount) DecryptKey(algorithm cryptogo.EncryptionAlgorithm, key []byte) ([]byte, error) { + return cryptogo.DecryptKey(algorithm, key, a.key) +} + +func (a *rsaAccount) Sign(data []byte) (cryptogo.SignatureAlgorithm, []byte, error) { + // Hash payload + hashed := cryptogo.Hash(data) + + algorithm := cryptogo.SignatureAlgorithm_SHA512WITHRSA_PSS + + // Sign hash of encrypted payload + signature, err := cryptogo.CreateSignature(algorithm, a.key, hashed) + if err != nil { + return cryptogo.SignatureAlgorithm_UNKNOWN_SIGNATURE, nil, err + } + + return algorithm, signature, nil +} diff --git a/vendor/aletheiaware.com/bcgo/bcutils.go b/vendor/aletheiaware.com/bcgo/bcutils.go index c8e8eaf..5032d77 100644 --- a/vendor/aletheiaware.com/bcgo/bcutils.go +++ b/vendor/aletheiaware.com/bcgo/bcutils.go @@ -20,9 +20,6 @@ package bcgo import ( "aletheiaware.com/cryptogo" "bufio" - "crypto/rand" - "crypto/rsa" - "crypto/sha512" "errors" "fmt" "github.com/golang/protobuf/proto" @@ -32,7 +29,7 @@ import ( "math/bits" "os" "os/user" - "path" + "path/filepath" "strconv" "strings" "time" @@ -139,14 +136,14 @@ func MoneyToString(currency string, amount int64) string { } func IsLive() bool { - return GetBooleanFlag(LIVE_FLAG) + return BooleanFlag(LIVE_FLAG) } func IsBeta() bool { - return GetBooleanFlag(BETA_FLAG) + return BooleanFlag(BETA_FLAG) } -func GetBooleanFlag(name string) bool { +func BooleanFlag(name string) bool { flag, ok := os.LookupEnv(name) if !ok { return false @@ -158,18 +155,18 @@ func GetBooleanFlag(name string) bool { return b } -func GetBCHost() string { +func BCHost() string { if IsLive() { return BC_HOST } return BC_HOST_TEST } -func GetBCWebsite() string { - return "https://" + GetBCHost() +func BCWebsite() string { + return "https://" + BCHost() } -func GetAlias() (string, error) { +func Alias() (string, error) { alias, ok := os.LookupEnv("ALIAS") if !ok { u, err := user.Current() @@ -181,22 +178,25 @@ func GetAlias() (string, error) { return alias, nil } -func GetRootDirectory() (string, error) { +func RootDirectory() (string, error) { root, ok := os.LookupEnv("ROOT_DIRECTORY") if !ok { u, err := user.Current() if err != nil { return "", err } - root = path.Join(u.HomeDir, "bc") + root = filepath.Join(u.HomeDir, "bc") + if _, err := os.Stat(root); os.IsNotExist(err) { + root = RootDirectoryForUser(u) + } } return root, nil } -func GetKeyDirectory(directory string) (string, error) { +func KeyDirectory(directory string) (string, error) { keystore, ok := os.LookupEnv("KEYS_DIRECTORY") if !ok { - keystore = path.Join(directory, "keys") + keystore = filepath.Join(directory, "keys") } if err := os.MkdirAll(keystore, os.ModePerm); err != nil { return "", err @@ -204,18 +204,18 @@ func GetKeyDirectory(directory string) (string, error) { return keystore, nil } -func GetCacheDirectory(directory string) (string, error) { +func CacheDirectory(directory string) (string, error) { cache, ok := os.LookupEnv("CACHE_DIRECTORY") if !ok { - cache = path.Join(directory, "cache") + cache = filepath.Join(directory, "cache") } return cache, nil } -func GetCertificateDirectory(directory string) (string, error) { +func CertificateDirectory(directory string) (string, error) { certs, ok := os.LookupEnv("CERTIFICATE_DIRECTORY") if !ok { - certs = path.Join(directory, "certificates") + certs = filepath.Join(directory, "certificates") } return certs, nil } @@ -230,7 +230,7 @@ func LoadConfig() error { return err } // Load Root Config - directory, err = GetRootDirectory() + directory, err = RootDirectory() if err != nil { return err } @@ -241,9 +241,9 @@ func LoadConfig() error { } func ReadConfig(directory string) error { - filepath := path.Join(directory, ".bc") - if _, err := os.Stat(filepath); err == nil { - file, err := os.Open(filepath) + path := filepath.Join(directory, "config") + if _, err := os.Stat(path); err == nil { + file, err := os.Open(path) if err != nil { return err } @@ -267,12 +267,12 @@ func ReadConfig(directory string) error { func SetupLogging(directory string) (*os.File, error) { store, ok := os.LookupEnv("LOG_DIRECTORY") if !ok { - store = path.Join(directory, "logs") + store = filepath.Join(directory, "logs") } if err := os.MkdirAll(store, os.ModePerm); err != nil { return nil, err } - logFile, err := os.OpenFile(path.Join(store, time.Now().UTC().Format(time.RFC3339)), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600) + logFile, err := os.OpenFile(filepath.Join(store, time.Now().UTC().Format(time.RFC3339)), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600) if err != nil { return nil, err } @@ -281,7 +281,7 @@ func SetupLogging(directory string) (*os.File, error) { return logFile, nil } -func GetPeers(directory string) ([]string, error) { +func Peers(directory string) ([]string, error) { env, ok := os.LookupEnv("PEERS") if ok { return SplitRemoveEmpty(env, ","), nil @@ -290,7 +290,7 @@ func GetPeers(directory string) ([]string, error) { if IsLive() { filename = "peers" } - filepath := path.Join(directory, filename) + filepath := filepath.Join(directory, filename) if _, err := os.Stat(filepath); os.IsNotExist(err) { return []string{}, nil } @@ -320,7 +320,7 @@ func AddPeer(directory, peer string) error { if IsLive() { filename = "peers" } - file, err := os.OpenFile(path.Join(directory, filename), os.O_APPEND|os.O_CREATE|os.O_WRONLY, os.ModePerm) + file, err := os.OpenFile(filepath.Join(directory, filename), os.O_APPEND|os.O_CREATE|os.O_WRONLY, os.ModePerm) if err != nil { return err } @@ -331,31 +331,8 @@ func AddPeer(directory, peer string) error { return nil } -func DecryptRecord(entry *BlockEntry, access *Record_Access, key *rsa.PrivateKey, callback func(*BlockEntry, []byte, []byte) error) error { - decryptedKey, err := cryptogo.DecryptKey(access.EncryptionAlgorithm, access.SecretKey, key) - if err != nil { - return err - } - record := entry.Record - switch record.EncryptionAlgorithm { - case cryptogo.EncryptionAlgorithm_AES_128_GCM_NOPADDING: - fallthrough - case cryptogo.EncryptionAlgorithm_AES_256_GCM_NOPADDING: - decryptedPayload, err := cryptogo.DecryptAESGCM(decryptedKey, record.Payload) - if err != nil { - return err - } - // Call callback - return callback(entry, decryptedKey, decryptedPayload) - case cryptogo.EncryptionAlgorithm_UNKNOWN_ENCRYPTION: - return callback(entry, nil, record.Payload) - default: - return fmt.Errorf(cryptogo.ERROR_UNSUPPORTED_ENCRYPTION, record.EncryptionAlgorithm.String()) - } -} - // Chunk the data from reader into individual records with their own secret key and access list -func CreateRecords(creatorAlias string, creatorKey *rsa.PrivateKey, access map[string]*rsa.PublicKey, references []*Reference, reader io.Reader, callback func([]byte, *Record) error) (int, error) { +func CreateRecords(creator Account, access []Identity, references []*Reference, reader io.Reader, callback func([]byte, *Record) error) (int, error) { payload := make([]byte, MAX_PAYLOAD_SIZE_BYTES) size := 0 for { @@ -369,7 +346,7 @@ func CreateRecords(creatorAlias string, creatorKey *rsa.PrivateKey, access map[s } } size = size + count - key, record, err := CreateRecord(Timestamp(), creatorAlias, creatorKey, access, references, payload[:count]) + key, record, err := CreateRecord(Timestamp(), creator, access, references, payload[:count]) if err != nil { return 0, err } @@ -380,7 +357,7 @@ func CreateRecords(creatorAlias string, creatorKey *rsa.PrivateKey, access map[s return size, nil } -func CreateRecord(timestamp uint64, creatorAlias string, creatorKey *rsa.PrivateKey, access map[string]*rsa.PublicKey, references []*Reference, payload []byte) ([]byte, *Record, error) { +func CreateRecord(timestamp uint64, creator Account, access []Identity, references []*Reference, payload []byte) ([]byte, *Record, error) { size := uint64(len(payload)) if size > MAX_PAYLOAD_SIZE_BYTES { return nil, nil, errors.New("Payload too large: " + BinarySizeToString(size) + " max: " + BinarySizeToString(MAX_PAYLOAD_SIZE_BYTES)) @@ -389,7 +366,7 @@ func CreateRecord(timestamp uint64, creatorAlias string, creatorKey *rsa.Private // Create record record := &Record{ Timestamp: timestamp, - Creator: creatorAlias, + Creator: creator.Alias(), Reference: references, } @@ -408,15 +385,15 @@ func CreateRecord(timestamp uint64, creatorAlias string, creatorKey *rsa.Private } // Grant access to each public key - for a, k := range access { - secretKey, err := rsa.EncryptOAEP(sha512.New(), rand.Reader, k, key, nil) + for _, a := range access { + algorithm, encrypted, err := a.EncryptKey(key) if err != nil { return nil, nil, err } record.Access = append(record.Access, &Record_Access{ - Alias: a, - SecretKey: secretKey, - EncryptionAlgorithm: cryptogo.EncryptionAlgorithm_RSA_ECB_OAEPPADDING, + Alias: a.Alias(), + SecretKey: encrypted, + EncryptionAlgorithm: algorithm, }) } record.EncryptionAlgorithm = cryptogo.EncryptionAlgorithm_AES_256_GCM_NOPADDING @@ -424,11 +401,7 @@ func CreateRecord(timestamp uint64, creatorAlias string, creatorKey *rsa.Private record.EncryptionAlgorithm = cryptogo.EncryptionAlgorithm_UNKNOWN_ENCRYPTION } - // Hash payload - hashed := cryptogo.Hash(payload) - - // Sign hash of encrypted payload - signature, err := cryptogo.CreateSignature(creatorKey, hashed, cryptogo.SignatureAlgorithm_SHA512WITHRSA_PSS) + algorithm, signature, err := creator.Sign(payload) if err != nil { return nil, nil, err } @@ -436,7 +409,7 @@ func CreateRecord(timestamp uint64, creatorAlias string, creatorKey *rsa.Private // Set payload and signature record.Payload = payload record.Signature = signature - record.SignatureAlgorithm = cryptogo.SignatureAlgorithm_SHA512WITHRSA_PSS + record.SignatureAlgorithm = algorithm if l, ok := os.LookupEnv(LIVE_FLAG); ok { record.Meta = map[string]string{ diff --git a/vendor/aletheiaware.com/bcgo/bcutils_android.go b/vendor/aletheiaware.com/bcgo/bcutils_android.go new file mode 100644 index 0000000..a39cb77 --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/bcutils_android.go @@ -0,0 +1,28 @@ +// +build android,!linux + +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bcgo + +import ( + "os/user" + "path/filepath" +) + +func RootDirectoryForUser(u *user.User) string { + return filepath.Join(u.HomeDir, "bc") +} diff --git a/vendor/aletheiaware.com/bcgo/bcutils_darwin.go b/vendor/aletheiaware.com/bcgo/bcutils_darwin.go new file mode 100644 index 0000000..a693800 --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/bcutils_darwin.go @@ -0,0 +1,28 @@ +// +build darwin + +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bcgo + +import ( + "os/user" + "path/filepath" +) + +func RootDirectoryForUser(u *user.User) string { + return filepath.Join(u.HomeDir, "Library", "Preferences", "bc") +} diff --git a/vendor/aletheiaware.com/bcgo/bcutils_ios.go b/vendor/aletheiaware.com/bcgo/bcutils_ios.go new file mode 100644 index 0000000..3291c72 --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/bcutils_ios.go @@ -0,0 +1,28 @@ +// +build ios + +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bcgo + +import ( + "os/user" + "path/filepath" +) + +func RootDirectoryForUser(u *user.User) string { + return filepath.Join(u.HomeDir, "bc") +} diff --git a/vendor/aletheiaware.com/bcgo/bcutils_linux.go b/vendor/aletheiaware.com/bcgo/bcutils_linux.go new file mode 100644 index 0000000..0240aea --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/bcutils_linux.go @@ -0,0 +1,28 @@ +// +build linux + +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bcgo + +import ( + "os/user" + "path/filepath" +) + +func RootDirectoryForUser(u *user.User) string { + return filepath.Join(u.HomeDir, ".config", "bc") +} diff --git a/vendor/aletheiaware.com/bcgo/bcutils_windows.go b/vendor/aletheiaware.com/bcgo/bcutils_windows.go new file mode 100644 index 0000000..e97482e --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/bcutils_windows.go @@ -0,0 +1,28 @@ +// +build windows + +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bcgo + +import ( + "os/user" + "path/filepath" +) + +func RootDirectoryForUser(u *user.User) string { + return filepath.Join(u.HomeDir, "AppData", "Roaming", "bc") +} diff --git a/vendor/aletheiaware.com/bcgo/cache.go b/vendor/aletheiaware.com/bcgo/cache.go index 5df171b..e7bb901 100644 --- a/vendor/aletheiaware.com/bcgo/cache.go +++ b/vendor/aletheiaware.com/bcgo/cache.go @@ -17,10 +17,10 @@ package bcgo type Cache interface { - GetHead(channel string) (*Reference, error) - GetBlock(hash []byte) (*Block, error) - GetBlockEntries(channel string, timestamp uint64) ([]*BlockEntry, error) - GetBlockContainingRecord(channel string, hash []byte) (*Block, error) + Head(channel string) (*Reference, error) + Block(hash []byte) (*Block, error) + BlockEntries(channel string, timestamp uint64) ([]*BlockEntry, error) + BlockContainingRecord(channel string, hash []byte) (*Block, error) PutHead(channel string, reference *Reference) error PutBlock(hash []byte, block *Block) error PutBlockEntry(channel string, entry *BlockEntry) error diff --git a/vendor/aletheiaware.com/bcgo/filecache.go b/vendor/aletheiaware.com/bcgo/cache/filesystem.go similarity index 81% rename from vendor/aletheiaware.com/bcgo/filecache.go rename to vendor/aletheiaware.com/bcgo/cache/filesystem.go index 7c20ac4..24e9602 100644 --- a/vendor/aletheiaware.com/bcgo/filecache.go +++ b/vendor/aletheiaware.com/bcgo/cache/filesystem.go @@ -1,5 +1,5 @@ /* - * Copyright 2019 Aletheia Ware LLC + * Copyright 2019-21 Aletheia Ware LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,9 +14,10 @@ * limitations under the License. */ -package bcgo +package cache import ( + "aletheiaware.com/bcgo" "encoding/base64" "github.com/golang/protobuf/proto" "io/ioutil" @@ -26,11 +27,11 @@ import ( "strings" ) -type FileCache struct { +type FileSystem struct { Directory string } -func NewFileCache(directory string) (*FileCache, error) { +func NewFileSystem(directory string) (*FileSystem, error) { // Create Block Cache if err := os.MkdirAll(path.Join(directory, "block"), os.ModePerm); err != nil { return nil, err @@ -39,33 +40,33 @@ func NewFileCache(directory string) (*FileCache, error) { if err := os.MkdirAll(path.Join(directory, "channel"), os.ModePerm); err != nil { return nil, err } - return &FileCache{ + return &FileSystem{ Directory: directory, }, nil } -func (f *FileCache) GetBlock(hash []byte) (*Block, error) { +func (f *FileSystem) Block(hash []byte) (*bcgo.Block, error) { // Read from file data, err := ioutil.ReadFile(path.Join(f.Directory, "block", base64.RawURLEncoding.EncodeToString(hash))) if err != nil { return nil, err } // Unmarshal into block - block := &Block{} + block := &bcgo.Block{} if err = proto.Unmarshal(data[:], block); err != nil { return nil, err } return block, nil } -func (f *FileCache) GetBlockEntries(channel string, timestamp uint64) ([]*BlockEntry, error) { +func (f *FileSystem) BlockEntries(channel string, timestamp uint64) ([]*bcgo.BlockEntry, error) { directory := path.Join(f.Directory, "entry", base64.RawURLEncoding.EncodeToString([]byte(channel))) // Read directory files, err := ioutil.ReadDir(directory) if err != nil { return nil, err } - var entries []*BlockEntry + var entries []*bcgo.BlockEntry for _, f := range files { t, err := strconv.ParseUint(f.Name(), 10, 64) if err != nil { @@ -78,7 +79,7 @@ func (f *FileCache) GetBlockEntries(channel string, timestamp uint64) ([]*BlockE return nil, err } // Unmarshal into entry - entry := &BlockEntry{} + entry := &bcgo.BlockEntry{} if err = proto.Unmarshal(data[:], entry); err != nil { return nil, err } @@ -88,29 +89,29 @@ func (f *FileCache) GetBlockEntries(channel string, timestamp uint64) ([]*BlockE return entries, nil } -func (f *FileCache) GetBlockContainingRecord(channel string, hash []byte) (*Block, error) { +func (f *FileSystem) BlockContainingRecord(channel string, hash []byte) (*bcgo.Block, error) { data, err := ioutil.ReadFile(path.Join(f.Directory, "mapping", base64.RawURLEncoding.EncodeToString([]byte(channel)), base64.RawURLEncoding.EncodeToString(hash))) if err != nil { return nil, err } - return f.GetBlock(data) + return f.Block(data) } -func (f *FileCache) GetHead(channel string) (*Reference, error) { +func (f *FileSystem) Head(channel string) (*bcgo.Reference, error) { // Read from file data, err := ioutil.ReadFile(path.Join(f.Directory, "channel", base64.RawURLEncoding.EncodeToString([]byte(channel)))) if err != nil { return nil, err } // Unmarshal into reference - reference := &Reference{} + reference := &bcgo.Reference{} if err = proto.Unmarshal(data[:], reference); err != nil { return nil, err } return reference, nil } -func (f *FileCache) PutBlock(hash []byte, block *Block) error { +func (f *FileSystem) PutBlock(hash []byte, block *bcgo.Block) error { directory := path.Join(f.Directory, "mapping", base64.RawURLEncoding.EncodeToString([]byte(block.ChannelName))) // Create mapping directory if err := os.MkdirAll(directory, os.ModePerm); err != nil { @@ -131,7 +132,7 @@ func (f *FileCache) PutBlock(hash []byte, block *Block) error { return ioutil.WriteFile(path.Join(f.Directory, "block", base64.RawURLEncoding.EncodeToString(hash)), data, os.ModePerm) } -func (f *FileCache) PutBlockEntry(channel string, entry *BlockEntry) error { +func (f *FileSystem) PutBlockEntry(channel string, entry *bcgo.BlockEntry) error { // Marshal into byte array data, err := proto.Marshal(entry) if err != nil { @@ -146,7 +147,7 @@ func (f *FileCache) PutBlockEntry(channel string, entry *BlockEntry) error { return ioutil.WriteFile(path.Join(directory, strconv.FormatUint(entry.Record.Timestamp, 10)), data, os.ModePerm) } -func (f *FileCache) PutHead(channel string, reference *Reference) error { +func (f *FileSystem) PutHead(channel string, reference *bcgo.Reference) error { // Marshal into byte array data, err := proto.Marshal(reference) if err != nil { @@ -156,12 +157,12 @@ func (f *FileCache) PutHead(channel string, reference *Reference) error { return ioutil.WriteFile(path.Join(f.Directory, "channel", base64.RawURLEncoding.EncodeToString([]byte(channel))), data, os.ModePerm) } -// func (f *FileCache) DeleteBlock(hash []byte) error { +// func (f *FileSystem) DeleteBlock(hash []byte) error { // // Delete file // return os.Remove(path.Join(f.Directory, "block", base64.RawURLEncoding.EncodeToString(hash))) // } -func (f *FileCache) MeasureStorageUsage(prefix string) (map[string]uint64, error) { +func (f *FileSystem) MeasureStorageUsage(prefix string) (map[string]uint64, error) { usage := make(map[string]uint64) files, err := ioutil.ReadDir(path.Join(f.Directory, "block")) if err != nil { @@ -172,7 +173,7 @@ func (f *FileCache) MeasureStorageUsage(prefix string) (map[string]uint64, error if err != nil { return nil, err } - block, err := f.GetBlock(hash) + block, err := f.Block(hash) if err != nil { return nil, err } diff --git a/vendor/aletheiaware.com/bcgo/cache/memory.go b/vendor/aletheiaware.com/bcgo/cache/memory.go new file mode 100644 index 0000000..0ecefc8 --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/cache/memory.go @@ -0,0 +1,100 @@ +/* + * Copyright 2019-21 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cache + +import ( + "aletheiaware.com/bcgo" + "encoding/base64" +) + +type Memory struct { + Blocks map[string]*bcgo.Block + Heads map[string]*bcgo.Reference + Entries map[string][]*bcgo.BlockEntry + Mapping map[string]*bcgo.Block +} + +func NewMemory(size int) *Memory { + // TODO separate sizes for blocks, heads, entries, mappings + // TODO implement LRU + // TODO implement cache levels where a memory cache sits above a file cache + return &Memory{ + Blocks: make(map[string]*bcgo.Block, size), + Heads: make(map[string]*bcgo.Reference, size), + Entries: make(map[string][]*bcgo.BlockEntry, size), + Mapping: make(map[string]*bcgo.Block, size), + } +} + +func (m *Memory) Block(hash []byte) (*bcgo.Block, error) { + key := base64.RawURLEncoding.EncodeToString(hash) + block, ok := m.Blocks[key] + if !ok { + return nil, bcgo.ErrNoSuchBlock{Hash: key} + } + return block, nil +} + +func (m *Memory) BlockEntries(channel string, timestamp uint64) ([]*bcgo.BlockEntry, error) { + var results []*bcgo.BlockEntry + for _, e := range m.Entries[channel] { + if e.Record.Timestamp >= timestamp { + results = append(results, e) + } + } + return results, nil +} + +func (m *Memory) BlockContainingRecord(channel string, hash []byte) (*bcgo.Block, error) { + key := base64.RawURLEncoding.EncodeToString(hash) + block, ok := m.Mapping[key] + if !ok { + return nil, bcgo.ErrNoSuchMapping{Hash: key} + } + return block, nil +} + +func (m *Memory) Head(channel string) (*bcgo.Reference, error) { + reference, ok := m.Heads[channel] + if !ok { + return nil, bcgo.ErrNoSuchHead{Channel: channel} + } + return reference, nil +} + +func (m *Memory) PutBlock(hash []byte, block *bcgo.Block) error { + m.Blocks[base64.RawURLEncoding.EncodeToString(hash)] = block + for _, e := range block.Entry { + m.Mapping[base64.RawURLEncoding.EncodeToString(e.RecordHash)] = block + } + return nil +} + +func (m *Memory) PutBlockEntry(channel string, entry *bcgo.BlockEntry) error { + m.Entries[channel] = append(m.Entries[channel], entry) + return nil +} + +func (m *Memory) PutHead(channel string, reference *bcgo.Reference) error { + m.Heads[channel] = reference + return nil +} + +// func (m *Memory) DeleteBlock(hash []byte) error { +// delete(m.Blocks, base64.RawURLEncoding.EncodeToString(hash)) +// return nil +// } diff --git a/vendor/aletheiaware.com/bcgo/channel.go b/vendor/aletheiaware.com/bcgo/channel.go index 734ae2a..20b0d37 100644 --- a/vendor/aletheiaware.com/bcgo/channel.go +++ b/vendor/aletheiaware.com/bcgo/channel.go @@ -19,119 +19,30 @@ package bcgo import ( "aletheiaware.com/cryptogo" "bytes" - "crypto/rsa" - "errors" "fmt" + "log" "reflect" "strings" "unicode" ) -const ( - ERROR_CHAIN_INVALID = "Chain invalid: %s" - ERROR_CHAIN_TOO_SHORT = "Chain too short to replace current head: %d vs %d" - ERROR_HASH_INCORRECT = "Hash doesn't match block hash" - ERROR_NAME_INCORRECT = "Name doesn't match channel name: %s vs %s" - ERROR_NAME_INVALID = "Name invalid: %s" -) - -type Channel struct { - Name string - Head []byte - Timestamp uint64 - Triggers []func() - Validators []Validator -} - -func NewChannel(name string) *Channel { - return &Channel{ - Name: name, - } -} - -func (c *Channel) String() string { - return c.Name -} - -func (c *Channel) AddTrigger(trigger func()) { - c.Triggers = append(c.Triggers, trigger) -} - -func (c *Channel) AddValidator(validator Validator) { - c.Validators = append(c.Validators, validator) -} - -// Validates name matches channel name and all characters are in the set [a-zA-Z0-9.-_] -func (c *Channel) ValidateName(name string) error { - if c.Name != name { - return fmt.Errorf(ERROR_NAME_INCORRECT, c.Name, name) - } - if strings.IndexFunc(name, func(r rune) bool { - return !unicode.IsLetter(r) && !unicode.IsDigit(r) && r != '.' && r != '-' && r != '_' - }) != -1 { - return fmt.Errorf(ERROR_NAME_INVALID, name) - } - return nil -} - -func (c *Channel) Update(cache Cache, network Network, head []byte, block *Block) error { - if bytes.Equal(c.Head, head) { - // Channel up to date - return nil - } - - if err := c.ValidateName(block.ChannelName); err != nil { - return err - } - - // Check hash matches block hash - h, err := cryptogo.HashProtobuf(block) - if err != nil { - return err - } - if !bytes.Equal(head, h) { - return errors.New(ERROR_HASH_INCORRECT) - } - if c.Head != nil { - b, err := cache.GetBlock(c.Head) - if err != nil { - return err - } - // Check block chain is longer than current head - if b != nil && b.Length >= block.Length { - return fmt.Errorf(ERROR_CHAIN_TOO_SHORT, block.Length, b.Length) - } - } - - for _, v := range c.Validators { - if err := v.Validate(c, cache, network, head, block); err != nil { - return fmt.Errorf(ERROR_CHAIN_INVALID, err.Error()) - } - } - - if err := cache.PutHead(c.Name, &Reference{ - Timestamp: block.Timestamp, - ChannelName: c.Name, - BlockHash: head, - }); err != nil { - return err - } - if err := cache.PutBlock(head, block); err != nil { - return err - } - c.update(block.Timestamp, head) - return nil +type Channel interface { + fmt.Stringer + Name() string + Head() []byte + Timestamp() uint64 + AddTrigger(func()) + AddValidator(Validator) + Update(Cache, Network, []byte, *Block) error + Set(uint64, []byte) + Load(Cache, Network) error + Refresh(Cache, Network) error + Pull(Cache, Network) error + Push(Cache, Network) error } -func (c *Channel) update(timestamp uint64, head []byte) { - c.Timestamp = timestamp - c.Head = head - for _, t := range c.Triggers { - t() - } -} - -func ReadKey(channel string, hash []byte, block *Block, cache Cache, network Network, alias string, key *rsa.PrivateKey, recordHash []byte, callback func([]byte) error) error { +func ReadKey(channel string, hash []byte, block *Block, cache Cache, network Network, account Account, recordHash []byte, callback func([]byte) error) error { + alias := account.Alias() return Iterate(channel, hash, block, cache, network, func(h []byte, b *Block) error { for _, entry := range b.Entry { if recordHash == nil || bytes.Equal(recordHash, entry.RecordHash) { @@ -143,13 +54,11 @@ func ReadKey(channel string, hash []byte, block *Block, cache Cache, network Net } else { for _, access := range entry.Record.Access { if alias == "" || alias == access.Alias { - decryptedKey, err := cryptogo.DecryptKey(access.EncryptionAlgorithm, access.SecretKey, key) + decryptedKey, err := account.DecryptKey(access.EncryptionAlgorithm, access.SecretKey) if err != nil { return err } - if err := callback(decryptedKey); err != nil { - return err - } + return callback(decryptedKey) } } } @@ -159,7 +68,8 @@ func ReadKey(channel string, hash []byte, block *Block, cache Cache, network Net }) } -func Read(channel string, hash []byte, block *Block, cache Cache, network Network, alias string, key *rsa.PrivateKey, recordHash []byte, callback func(*BlockEntry, []byte, []byte) error) error { +func Read(channel string, hash []byte, block *Block, cache Cache, network Network, account Account, recordHash []byte, callback func(*BlockEntry, []byte, []byte) error) error { + alias := account.Alias() // Decrypt each record in chain and pass to the given callback return Iterate(channel, hash, block, cache, network, func(h []byte, b *Block) error { for _, entry := range b.Entry { @@ -172,9 +82,15 @@ func Read(channel string, hash []byte, block *Block, cache Cache, network Networ } else { for _, access := range entry.Record.Access { if alias == "" || alias == access.Alias { - if err := DecryptRecord(entry, access, key, callback); err != nil { + decryptedKey, err := account.DecryptKey(access.EncryptionAlgorithm, access.SecretKey) + if err != nil { + return err + } + decryptedPayload, err := account.Decrypt(entry.Record.EncryptionAlgorithm, entry.Record.Payload, decryptedKey) + if err != nil { return err } + return callback(entry, decryptedKey, decryptedPayload) } } } @@ -184,13 +100,6 @@ func Read(channel string, hash []byte, block *Block, cache Cache, network Networ }) } -type StopIterationError struct { -} - -func (e StopIterationError) Error() string { - return "Stop Iteration" -} - func Iterate(channel string, hash []byte, block *Block, cache Cache, network Network, callback func([]byte, *Block) error) error { // Iterate throught each block in the chain if hash == nil { @@ -199,7 +108,7 @@ func Iterate(channel string, hash []byte, block *Block, cache Cache, network Net var err error b := block if b == nil { - b, err = GetBlock(channel, cache, network, hash) + b, err = LoadBlock(channel, cache, network, hash) if err != nil { return err } @@ -210,7 +119,7 @@ func Iterate(channel string, hash []byte, block *Block, cache Cache, network Net } hash = b.Previous if hash != nil && len(hash) > 0 { - b, err = GetBlock(channel, cache, network, hash) + b, err = LoadBlock(channel, cache, network, hash) if err != nil { return err } @@ -233,7 +142,7 @@ func IterateChronologically(channel string, hash []byte, block *Block, cache Cac // Iterate list of block hashes chronologically for i := len(hashes) - 1; i >= 0; i-- { hash := hashes[i] - block, err := GetBlock(channel, cache, network, hash) + block, err := LoadBlock(channel, cache, network, hash) if err != nil { return err } @@ -244,55 +153,37 @@ func IterateChronologically(channel string, hash []byte, block *Block, cache Cac return nil } -func (c *Channel) LoadCachedHead(cache Cache) error { - reference, err := cache.GetHead(c.Name) - if err != nil { - return err - } - c.update(reference.Timestamp, reference.BlockHash) - return nil -} - -func (c *Channel) LoadHead(cache Cache, network Network) error { - reference, err := GetHeadReference(c.Name, cache, network) - if err != nil { - return err - } - c.update(reference.Timestamp, reference.BlockHash) - return nil -} - -func GetHeadReference(channel string, cache Cache, network Network) (*Reference, error) { - reference, err := cache.GetHead(channel) +func LoadHead(channel string, cache Cache, network Network) (*Reference, error) { + reference, err := cache.Head(channel) if err != nil { if network == nil || reflect.ValueOf(network).IsNil() { return nil, err } else { - fmt.Println(err) + log.Println(err) } } else { return reference, nil } - reference, err = network.GetHead(channel) + reference, err = network.Head(channel) if err != nil { return nil, err } return reference, nil } -func GetBlock(channel string, cache Cache, network Network, hash []byte) (*Block, error) { - b, err := cache.GetBlock(hash) +func LoadBlock(channel string, cache Cache, network Network, hash []byte) (*Block, error) { + b, err := cache.Block(hash) if err != nil { if network == nil || reflect.ValueOf(network).IsNil() { return nil, err } else { - fmt.Println(err) + log.Println(err) } } else { return b, nil } - b, err = network.GetBlock(&Reference{ + b, err = network.Block(&Reference{ ChannelName: channel, BlockHash: hash, }) @@ -307,19 +198,19 @@ func GetBlock(channel string, cache Cache, network Network, hash []byte) (*Block return b, nil } -func GetBlockContainingRecord(channel string, cache Cache, network Network, hash []byte) (*Block, error) { - b, err := cache.GetBlockContainingRecord(channel, hash) +func LoadBlockContainingRecord(channel string, cache Cache, network Network, hash []byte) (*Block, error) { + b, err := cache.BlockContainingRecord(channel, hash) if err != nil { if network == nil || reflect.ValueOf(network).IsNil() { return nil, err } else { - fmt.Println(err) + log.Println(err) } } else { return b, nil } - b, err = network.GetBlock(&Reference{ + b, err = network.Block(&Reference{ ChannelName: channel, RecordHash: hash, }) @@ -339,6 +230,16 @@ func GetBlockContainingRecord(channel string, cache Cache, network Network, hash return b, nil } +// ValidateName ensures all characters are in the set [a-zA-Z0-9.-_] +func ValidateName(name string) error { + if strings.IndexFunc(name, func(r rune) bool { + return !unicode.IsLetter(r) && !unicode.IsDigit(r) && r != '.' && r != '-' && r != '_' + }) != -1 { + return ErrChannelNameInvalid{name} + } + return nil +} + func WriteRecord(channel string, cache Cache, record *Record) (*Reference, error) { hash, err := cryptogo.HashProtobuf(record) if err != nil { @@ -356,67 +257,3 @@ func WriteRecord(channel string, cache Cache, record *Record) (*Reference, error RecordHash: hash, }, nil } - -func (c *Channel) Refresh(cache Cache, network Network) error { - // Load Channel - err := c.LoadCachedHead(cache) - // Pull from network regardless of above err - if network == nil || reflect.ValueOf(network).IsNil() { - return err - } - // Pull Channel - return c.Pull(cache, network) -} - -func (c *Channel) Pull(cache Cache, network Network) error { - if network == nil || reflect.ValueOf(network).IsNil() { - return nil - } - reference, err := network.GetHead(c.Name) - if err != nil { - return err - } - hash := reference.BlockHash - if bytes.Equal(c.Head, hash) { - // Channel up-to-date - return nil - } - // Load head block - block, err := GetBlock(c.Name, cache, network, hash) - if err != nil { - return err - } - // Ensure all previous blocks are loaded - b := block - for b != nil { - h := b.Previous - if h != nil && len(h) > 0 { - b, err = GetBlock(c.Name, cache, network, h) - if err != nil { - return err - } - } else { - b = nil - } - } - if err := c.Update(cache, network, hash, block); err != nil { - return err - } - return nil -} - -func (c *Channel) Push(cache Cache, network Network) error { - hash := c.Head - if hash == nil { - reference, err := cache.GetHead(c.Name) - if err != nil { - return err - } - hash = reference.BlockHash - } - block, err := cache.GetBlock(hash) - if err != nil { - return err - } - return network.Broadcast(c, cache, hash, block) -} diff --git a/vendor/aletheiaware.com/bcgo/channel/channel.go b/vendor/aletheiaware.com/bcgo/channel/channel.go new file mode 100644 index 0000000..9cd6a46 --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/channel/channel.go @@ -0,0 +1,223 @@ +/* + * Copyright 2019-21 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package channel + +import ( + "aletheiaware.com/bcgo" + "aletheiaware.com/cryptogo" + "bytes" + "reflect" + "sync" +) + +type channel struct { + name string + head []byte + timestamp uint64 + triggers []func() + validators []bcgo.Validator + lock sync.Mutex +} + +func New(name string) bcgo.Channel { + return &channel{ + name: name, + } +} + +func (c *channel) Name() string { + return c.name +} + +func (c *channel) Head() []byte { + return c.head +} + +func (c *channel) Timestamp() uint64 { + return c.timestamp +} + +func (c *channel) String() string { + return c.name +} + +func (c *channel) AddTrigger(trigger func()) { + c.triggers = append(c.triggers, trigger) + trigger() +} + +func (c *channel) AddValidator(validator bcgo.Validator) { + c.validators = append(c.validators, validator) +} + +func (c *channel) Update(cache bcgo.Cache, network bcgo.Network, head []byte, block *bcgo.Block) error { + c.lock.Lock() + defer c.lock.Unlock() + if bytes.Equal(c.head, head) { + // Channel up to date + return nil + } + + if c.name != block.ChannelName { + return bcgo.ErrChannelNameIncorrect{Expected: c.name, Actual: block.ChannelName} + } + + if err := bcgo.ValidateName(block.ChannelName); err != nil { + return err + } + + // Check hash matches block hash + h, err := cryptogo.HashProtobuf(block) + if err != nil { + return err + } + if !bytes.Equal(head, h) { + return bcgo.ErrBlockHashIncorrect{} + } + + // Check block is valid + for _, v := range c.validators { + if err := v.Validate(c, cache, network, head, block); err != nil { + return bcgo.ErrChainInvalid{Reason: err.Error()} + } + } + + if c.head != nil { + b, err := cache.Block(c.head) + if err != nil { + return err + } + // Check block chain is longer than current head + if b != nil && b.Length >= block.Length { + valid := true + // Check current head is still valid + for _, v := range c.validators { + if err := v.Validate(c, cache, network, c.head, b); err != nil { + valid = false + } + } + if valid { + // Current head is still valid and update is not long enough to replace it + return bcgo.ErrChainTooShort{LengthA: b.Length, LengthB: block.Length} + } + } + } + + if err := cache.PutHead(c.name, &bcgo.Reference{ + Timestamp: block.Timestamp, + ChannelName: c.name, + BlockHash: head, + }); err != nil { + return err + } + if err := cache.PutBlock(head, block); err != nil { + return err + } + c.Set(block.Timestamp, head) + return nil +} + +func (c *channel) Load(cache bcgo.Cache, network bcgo.Network) error { + reference, err := bcgo.LoadHead(c.name, cache, network) + if err != nil { + return err + } + if c.timestamp < reference.Timestamp { + c.Set(reference.Timestamp, reference.BlockHash) + } + return nil +} + +func (c *channel) Refresh(cache bcgo.Cache, network bcgo.Network) error { + // Load Channel + err := c.Load(cache, nil) + // Pull from network regardless of above err + if network == nil || reflect.ValueOf(network).IsNil() { + return err + } + // Pull Channel + err = c.Pull(cache, network) + switch e := err.(type) { + case bcgo.ErrChainTooShort: + if e.LengthA > e.LengthB { + // The local chain is longer than the remote, push local chain to remote. + err = c.Push(cache, network) + } + } + return err +} + +func (c *channel) Pull(cache bcgo.Cache, network bcgo.Network) error { + if network == nil || reflect.ValueOf(network).IsNil() { + return nil + } + reference, err := network.Head(c.name) + if err != nil { + return err + } + hash := reference.BlockHash + if bytes.Equal(c.head, hash) { + // Channel up-to-date + return nil + } + // Load head block + block, err := bcgo.LoadBlock(c.name, cache, network, hash) + if err != nil { + return err + } + // Ensure all previous blocks are loaded + b := block + for b != nil { + h := b.Previous + if h != nil && len(h) > 0 { + b, err = bcgo.LoadBlock(c.name, cache, network, h) + if err != nil { + return err + } + } else { + b = nil + } + } + if err := c.Update(cache, network, hash, block); err != nil { + return err + } + return nil +} + +func (c *channel) Push(cache bcgo.Cache, network bcgo.Network) error { + hash := c.head + if hash == nil { + reference, err := cache.Head(c.name) + if err != nil { + return err + } + hash = reference.BlockHash + } + block, err := cache.Block(hash) + if err != nil { + return err + } + return network.Broadcast(c, cache, hash, block) +} + +func (c *channel) Set(timestamp uint64, head []byte) { + c.timestamp = timestamp + c.head = head + for _, t := range c.triggers { + t() + } +} diff --git a/vendor/aletheiaware.com/bcgo/channel/pow.go b/vendor/aletheiaware.com/bcgo/channel/pow.go new file mode 100644 index 0000000..3f37e49 --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/channel/pow.go @@ -0,0 +1,28 @@ +/* + * Copyright 2019-21 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package channel + +import ( + "aletheiaware.com/bcgo" + "aletheiaware.com/bcgo/validation" +) + +func NewPoW(name string, threshold uint64) bcgo.Channel { + c := New(name) + c.AddValidator(validation.NewPoW(threshold)) + return c +} diff --git a/vendor/aletheiaware.com/bcgo/errors.go b/vendor/aletheiaware.com/bcgo/errors.go new file mode 100644 index 0000000..b96fe34 --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/errors.go @@ -0,0 +1,153 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bcgo + +import "fmt" + +// ErrBlockHashIncorrect is returned when the given hash does not match the hash of the given block. +type ErrBlockHashIncorrect struct { +} + +func (e ErrBlockHashIncorrect) Error() string { + return "Hash doesn't match block hash" +} + +// ErrChainInvalid is returned when a block fails validation for some reason. +type ErrChainInvalid struct { + Reason string +} + +func (e ErrChainInvalid) Error() string { + return fmt.Sprintf("Chain invalid: %s", e.Reason) +} + +// ErrChainTooShort is returned when a new chain is shorter the channel's current head. +type ErrChainTooShort struct { + LengthA, LengthB uint64 +} + +func (e ErrChainTooShort) Error() string { + return fmt.Sprintf("Chain too short to replace current head: %d vs %d", e.LengthA, e.LengthB) +} + +// ErrChannelNameIncorrect is returned when a block channel name doesn't match the channel. +type ErrChannelNameIncorrect struct { + Expected, Actual string +} + +func (e ErrChannelNameIncorrect) Error() string { + return fmt.Sprintf("Name doesn't match channel name: %s vs %s", e.Expected, e.Actual) +} + +// ErrChannelNameInvalid is returned when a channel name is too long or includes unsupported characters. +type ErrChannelNameInvalid struct { + Reason string +} + +func (e ErrChannelNameInvalid) Error() string { + return fmt.Sprintf("Name invalid: %s", e.Reason) +} + +// ErrChannelOutOfDate is returned when a broadcast fails due to the network +// having a more up-to-date version of the channel. +type ErrChannelOutOfDate struct { + Channel string +} + +func (e ErrChannelOutOfDate) Error() string { + return fmt.Sprintf("Channel out of date: %s", e.Channel) +} + +// ErrBlockTooLarge is returned when the Block exceeds the size limit. +type ErrBlockTooLarge struct { + Size, Max uint64 +} + +func (e ErrBlockTooLarge) Error() string { + return fmt.Sprintf("Block too large: %s max: %s", BinarySizeToString(e.Size), BinarySizeToString(e.Max)) +} + +// ErrPayloadTooLarge is returned when the Payload exceeds the size limit. +type ErrPayloadTooLarge struct { + Size, Max uint64 +} + +func (e ErrPayloadTooLarge) Error() string { + return fmt.Sprintf("Payload too large: %s max: %s", BinarySizeToString(e.Size), BinarySizeToString(e.Max)) +} + +// ErrNoSuchChannel is returned when a channel with the given name cannot be found. +type ErrNoSuchChannel struct { + Channel string +} + +func (e ErrNoSuchChannel) Error() string { + return fmt.Sprintf("No such channel: %s", e.Channel) +} + +// ErrNoSuchBlock is returned when a block with the given hash cannot be found. +type ErrNoSuchBlock struct { + Hash string +} + +func (e ErrNoSuchBlock) Error() string { + return fmt.Sprintf("No such block: %s", e.Hash) +} + +// ErrNoSuchHead is returned when a head with the given name cannot be found. +type ErrNoSuchHead struct { + Channel string +} + +func (e ErrNoSuchHead) Error() string { + return fmt.Sprintf("No such head: %s", e.Channel) +} + +// ErrNoSuchMapping is returned when a mapping with the given hash cannot be found. +type ErrNoSuchMapping struct { + Hash string +} + +func (e ErrNoSuchMapping) Error() string { + return fmt.Sprintf("No such record to block mapping: %s", e.Hash) +} + +// ErrNoEntriesToMine is returned when a mining operation fails due to a lack of entries. +type ErrNoEntriesToMine struct { + Channel string +} + +func (e ErrNoEntriesToMine) Error() string { + return fmt.Sprintf("No entries to mine for channel: %s", e.Channel) +} + +// ErrNonceWrapAround is returned when a mining operation fails after attempting every possible nonce. +type ErrNonceWrapAround struct { +} + +func (e ErrNonceWrapAround) Error() string { + return "Nonce wrapped around before reaching threshold" +} + +// ErrStopIteration is used by callbacks to indicate that their iteration +// through a channel should stop, typically because the result has been found. +type ErrStopIteration struct { +} + +func (e ErrStopIteration) Error() string { + return "Stop Iteration" +} diff --git a/vendor/aletheiaware.com/bcgo/go.mod b/vendor/aletheiaware.com/bcgo/go.mod index 3605806..2370e3e 100644 --- a/vendor/aletheiaware.com/bcgo/go.mod +++ b/vendor/aletheiaware.com/bcgo/go.mod @@ -3,7 +3,8 @@ module aletheiaware.com/bcgo go 1.14 require ( - aletheiaware.com/cryptogo v1.1.1 - aletheiaware.com/testinggo v1.1.2 - github.com/golang/protobuf v1.4.3 + aletheiaware.com/cryptogo v1.2.2 + aletheiaware.com/testinggo v1.2.2 + github.com/golang/protobuf v1.5.2 + github.com/stretchr/testify v1.7.0 ) diff --git a/vendor/aletheiaware.com/bcgo/go.sum b/vendor/aletheiaware.com/bcgo/go.sum index 705cf3b..b9a2016 100644 --- a/vendor/aletheiaware.com/bcgo/go.sum +++ b/vendor/aletheiaware.com/bcgo/go.sum @@ -1,34 +1,34 @@ -aletheiaware.com/cryptogo v1.1.1 h1:XrzGXcTgYQbuL3tQv/idVzAIblb2k+o77iigiQiXTUQ= -aletheiaware.com/cryptogo v1.1.1/go.mod h1:sT8jDe5zWSIswZDAilLwfX2N6l4WOFQBm+4lYxx1Ae0= -aletheiaware.com/testinggo v1.1.2 h1:/zCBvslySEY4uJ2qnnyvhFdgIERa/jzlgHBOmS4lL1k= -aletheiaware.com/testinggo v1.1.2/go.mod h1:bqmrqRyMkGbTa9E/1D8xHE0KLmOw+HRG0skc/XwrdcY= -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.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +aletheiaware.com/cryptogo v1.2.2 h1:d7vEEgf3bZFnLk+HG1wCAY/pgRz+zNYvKFpxsli3Mng= +aletheiaware.com/cryptogo v1.2.2/go.mod h1:B1mJVIsfEDJoovkD2fLsZXgXxR1AAe2cDmjFwt7Eau4= +aletheiaware.com/testinggo v1.2.2 h1:w+ir8ehcnIcZ+jTjalGWAkh3So9PaJm5g3CPgLnPtXE= +aletheiaware.com/testinggo v1.2.2/go.mod h1:TijVTRIGnue9UHlxT9YgLp5VGWOo4PI9VRflCm4v4xo= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc h1:+q90ECDSAQirdykUN6sPEiBXBsp8Csjcca8Oy7bgLTA= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/aletheiaware.com/bcgo/identity.go b/vendor/aletheiaware.com/bcgo/identity.go new file mode 100644 index 0000000..20ea2bc --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/identity.go @@ -0,0 +1,35 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bcgo + +import "aletheiaware.com/cryptogo" + +type Identity interface { + Alias() string + PublicKey() (cryptogo.PublicKeyFormat, []byte, error) + // Encrypt takes a Plaintext Payload + // A new AES 256bit Symmetric Key is generated, used to encrypt the Payload. + // Encrypt returns the Encryption Algorithm, Encrypted Payload, Key used, or an error. + Encrypt([]byte) (cryptogo.EncryptionAlgorithm, []byte, []byte, error) + // Encrypt takes a Plaintext key + // The given key is encrypted with this Identity's Public Key + // EncryptKey returns the Encryption Algorithm and Encrypted Key, or an error. + EncryptKey([]byte) (cryptogo.EncryptionAlgorithm, []byte, error) + // Verify takes a Signature Algorithm, Payload, and Signature. + // Verify returns an error if the signature cannot be verified. + Verify(cryptogo.SignatureAlgorithm, []byte, []byte) error +} diff --git a/vendor/aletheiaware.com/bcgo/identity/rsa.go b/vendor/aletheiaware.com/bcgo/identity/rsa.go new file mode 100644 index 0000000..0f9f5d6 --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/identity/rsa.go @@ -0,0 +1,75 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package identity + +import ( + "aletheiaware.com/bcgo" + "aletheiaware.com/cryptogo" + "crypto/rand" + "crypto/rsa" + "crypto/sha512" +) + +type rsaIdentity struct { + alias string + key *rsa.PublicKey +} + +func NewRSA(alias string, key *rsa.PublicKey) bcgo.Identity { + return &rsaIdentity{ + alias: alias, + key: key, + } +} + +func (a *rsaIdentity) Alias() string { + return a.alias +} + +func (a *rsaIdentity) PublicKey() (cryptogo.PublicKeyFormat, []byte, error) { + bytes, err := cryptogo.RSAPublicKeyToPKIXBytes(a.key) + if err != nil { + return cryptogo.PublicKeyFormat_UNKNOWN_PUBLIC_KEY_FORMAT, nil, err + } + return cryptogo.PublicKeyFormat_PKIX, bytes, nil +} + +func (a *rsaIdentity) Encrypt(payload []byte) (cryptogo.EncryptionAlgorithm, []byte, []byte, error) { + key, err := cryptogo.GenerateRandomKey(cryptogo.AES_256_KEY_SIZE_BYTES) + if err != nil { + return cryptogo.EncryptionAlgorithm_UNKNOWN_ENCRYPTION, nil, nil, err + } + + encryptedPayload, err := cryptogo.EncryptAESGCM(key, payload) + if err != nil { + return cryptogo.EncryptionAlgorithm_UNKNOWN_ENCRYPTION, nil, nil, err + } + + return cryptogo.EncryptionAlgorithm_AES_256_GCM_NOPADDING, encryptedPayload, key, nil +} + +func (a *rsaIdentity) EncryptKey(key []byte) (cryptogo.EncryptionAlgorithm, []byte, error) { + encrypted, err := rsa.EncryptOAEP(sha512.New(), rand.Reader, a.key, key, nil) + if err != nil { + return cryptogo.EncryptionAlgorithm_UNKNOWN_ENCRYPTION, nil, err + } + return cryptogo.EncryptionAlgorithm_RSA_ECB_OAEPPADDING, encrypted, nil +} + +func (a *rsaIdentity) Verify(algorithm cryptogo.SignatureAlgorithm, data, signature []byte) error { + return cryptogo.VerifySignature(algorithm, a.key, data, signature) +} diff --git a/vendor/aletheiaware.com/bcgo/logger.go b/vendor/aletheiaware.com/bcgo/logger.go new file mode 100644 index 0000000..906d0ac --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/logger.go @@ -0,0 +1,37 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bcgo + +import ( + "encoding/base64" + "log" +) + +type LoggingMiningListener struct { +} + +func (l *LoggingMiningListener) OnMiningStarted(channel Channel, size uint64) { + log.Printf("Mining %s %s\n", channel.Name(), BinarySizeToString(size)) +} + +func (l *LoggingMiningListener) OnNewMaxOnes(channel Channel, nonce, ones uint64) { + log.Printf("Mining %s %d %d/512\n", channel.Name(), nonce, ones) +} + +func (l *LoggingMiningListener) OnMiningThresholdReached(channel Channel, hash []byte, block *Block) { + log.Printf("Mined %s %s %s\n", channel.Name(), TimestampToString(block.Timestamp), base64.RawURLEncoding.EncodeToString(hash)) +} diff --git a/vendor/aletheiaware.com/bcgo/memorycache.go b/vendor/aletheiaware.com/bcgo/memorycache.go deleted file mode 100644 index d00259c..0000000 --- a/vendor/aletheiaware.com/bcgo/memorycache.go +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2019 Aletheia Ware LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package bcgo - -import ( - "encoding/base64" - "fmt" -) - -const ( - ERROR_BLOCK_NOT_FOUND = "Block not found %s" - ERROR_HEAD_NOT_FOUND = "Head not found %s" - ERROR_RECORD_TO_BLOCK_MAPPING_NOT_FOUND = "Record to Block Mapping not found %s" -) - -type MemoryCache struct { - Blocks map[string]*Block - Heads map[string]*Reference - Entries map[string][]*BlockEntry - Mapping map[string]*Block -} - -func NewMemoryCache(size int) *MemoryCache { - // TODO size for blocks, heads, entries - // TODO implement LRU - // TODO implement cache levels where - return &MemoryCache{ - Blocks: make(map[string]*Block, size), - Heads: make(map[string]*Reference, size), - Entries: make(map[string][]*BlockEntry, size), - Mapping: make(map[string]*Block, size), - } -} - -func (m *MemoryCache) GetBlock(hash []byte) (*Block, error) { - key := base64.RawURLEncoding.EncodeToString(hash) - block, ok := m.Blocks[key] - if !ok { - return nil, fmt.Errorf(ERROR_BLOCK_NOT_FOUND, key) - } - return block, nil -} - -func (m *MemoryCache) GetBlockEntries(channel string, timestamp uint64) ([]*BlockEntry, error) { - var results []*BlockEntry - for _, e := range m.Entries[channel] { - if e.Record.Timestamp >= timestamp { - results = append(results, e) - } - } - return results, nil -} - -func (m *MemoryCache) GetBlockContainingRecord(channel string, hash []byte) (*Block, error) { - key := base64.RawURLEncoding.EncodeToString(hash) - block, ok := m.Mapping[key] - if !ok { - return nil, fmt.Errorf(ERROR_RECORD_TO_BLOCK_MAPPING_NOT_FOUND, key) - } - return block, nil -} - -func (m *MemoryCache) GetHead(channel string) (*Reference, error) { - reference, ok := m.Heads[channel] - if !ok { - return nil, fmt.Errorf(ERROR_HEAD_NOT_FOUND, channel) - } - return reference, nil -} - -func (m *MemoryCache) PutBlock(hash []byte, block *Block) error { - m.Blocks[base64.RawURLEncoding.EncodeToString(hash)] = block - for _, e := range block.Entry { - m.Mapping[base64.RawURLEncoding.EncodeToString(e.RecordHash)] = block - } - return nil -} - -func (m *MemoryCache) PutBlockEntry(channel string, entry *BlockEntry) error { - m.Entries[channel] = append(m.Entries[channel], entry) - return nil -} - -func (m *MemoryCache) PutHead(channel string, reference *Reference) error { - m.Heads[channel] = reference - return nil -} - -// func (m *MemoryCache) DeleteBlock(hash []byte) error { -// delete(m.Blocks, base64.RawURLEncoding.EncodeToString(hash)) -// return nil -// } diff --git a/vendor/aletheiaware.com/bcgo/mining.go b/vendor/aletheiaware.com/bcgo/mining.go new file mode 100644 index 0000000..8b530bb --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/mining.go @@ -0,0 +1,156 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package bcgo + +import ( + "aletheiaware.com/cryptogo" + "github.com/golang/protobuf/proto" + "sort" +) + +type MiningListener interface { + OnMiningStarted(channel Channel, size uint64) + OnNewMaxOnes(channel Channel, nonce, ones uint64) + OnMiningThresholdReached(channel Channel, hash []byte, block *Block) +} + +func MineProto(node Node, channel Channel, threshold uint64, listener MiningListener, access []Identity, references []*Reference, message proto.Message) error { + data, err := proto.Marshal(message) + if err != nil { + return err + } + + if _, err := node.Write(Timestamp(), channel, access, references, data); err != nil { + return err + } + + if _, _, err := Mine(node, channel, threshold, listener); err != nil { + return err + } + + if err := channel.Push(node.Cache(), node.Network()); err != nil { + return err + } + return nil +} + +func LastMinedTimestamp(node Node, channel Channel) (uint64, error) { + alias := node.Account().Alias() + var timestamp uint64 + // Iterate through the chain to find the most recent block mined by this node + if err := Iterate(channel.Name(), channel.Head(), nil, node.Cache(), node.Network(), func(h []byte, b *Block) error { + if b.Miner == alias { + timestamp = b.Timestamp + return ErrStopIteration{} + } + return nil + }); err != nil { + switch err.(type) { + case ErrStopIteration: + // Do nothing + break + default: + return 0, err + } + } + return timestamp, nil +} + +func Mine(node Node, channel Channel, threshold uint64, listener MiningListener) ([]byte, *Block, error) { + timestamp, err := LastMinedTimestamp(node, channel) + if err != nil { + return nil, nil, err + } + + entries, err := node.Cache().BlockEntries(channel.Name(), timestamp) + if err != nil { + return nil, nil, err + } + + // Sort by timestamp + sort.Slice(entries, func(i, j int) bool { + return entries[i].Record.Timestamp < entries[j].Record.Timestamp + }) + + return MineEntries(node, channel, threshold, listener, entries) +} + +func MineEntries(node Node, channel Channel, threshold uint64, listener MiningListener, entries []*BlockEntry) ([]byte, *Block, error) { + if len(entries) == 0 { + return nil, nil, ErrNoEntriesToMine{channel.Name()} + } + + // TODO check record signature of each entry + + block := &Block{ + Timestamp: Timestamp(), + ChannelName: channel.Name(), + Length: 1, + Miner: node.Account().Alias(), + Entry: entries, + } + + previousHash := channel.Head() + if previousHash != nil { + previousBlock, err := node.Cache().Block(previousHash) + if err != nil { + return nil, nil, err + } + block.Length = previousBlock.Length + 1 + block.Previous = previousHash + } + + return MineBlock(node, channel, threshold, listener, block) +} + +func MineBlock(node Node, channel Channel, threshold uint64, listener MiningListener, block *Block) ([]byte, *Block, error) { + size := uint64(proto.Size(block)) + if size > MAX_BLOCK_SIZE_BYTES { + return nil, nil, ErrBlockTooLarge{size, MAX_BLOCK_SIZE_BYTES} + } + + if listener != nil { + listener.OnMiningStarted(channel, size) + } + + var max uint64 + // TODO only mine as long as channel head has not changed. + for nonce := uint64(1); nonce > 0; nonce++ { + block.Nonce = nonce + hash, err := cryptogo.HashProtobuf(block) + if err != nil { + return nil, nil, err + } + ones := Ones(hash) + if ones > max { + if listener != nil { + listener.OnNewMaxOnes(channel, nonce, ones) + } + max = ones + } + if ones > threshold { + if listener != nil { + listener.OnMiningThresholdReached(channel, hash, block) + } + if err := channel.Update(node.Cache(), node.Network(), hash, block); err != nil { + return nil, nil, err + } + return hash, block, nil + } + } + return nil, nil, ErrNonceWrapAround{} +} diff --git a/vendor/aletheiaware.com/bcgo/network.go b/vendor/aletheiaware.com/bcgo/network.go index a4ebc51..6321bdc 100644 --- a/vendor/aletheiaware.com/bcgo/network.go +++ b/vendor/aletheiaware.com/bcgo/network.go @@ -16,15 +16,11 @@ package bcgo -const ( - ERROR_CHANNEL_OUT_OF_DATE = "Channel out of date" -) - type Network interface { // Requests the head hash of the given channel - GetHead(channel string) (*Reference, error) + Head(channel string) (*Reference, error) // Requests the block from the given reference - GetBlock(reference *Reference) (*Block, error) + Block(reference *Reference) (*Block, error) // Broadcasts the channel update to the network - Broadcast(channel *Channel, cache Cache, hash []byte, block *Block) error + Broadcast(channel Channel, cache Cache, hash []byte, block *Block) error } diff --git a/vendor/aletheiaware.com/bcgo/tcpnetwork.go b/vendor/aletheiaware.com/bcgo/network/tcp.go similarity index 54% rename from vendor/aletheiaware.com/bcgo/tcpnetwork.go rename to vendor/aletheiaware.com/bcgo/network/tcp.go index 90d66b2..b6a84c8 100644 --- a/vendor/aletheiaware.com/bcgo/tcpnetwork.go +++ b/vendor/aletheiaware.com/bcgo/network/tcp.go @@ -1,5 +1,5 @@ /* - * Copyright 2019 Aletheia Ware LLC + * Copyright 2019-21 Aletheia Ware LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,18 +14,20 @@ * limitations under the License. */ -package bcgo +package network import ( + "aletheiaware.com/bcgo" "bufio" "bytes" "encoding/base64" - "errors" "fmt" "io" + "log" "net" "sort" "strconv" + "sync" "time" ) @@ -38,42 +40,50 @@ const ( PORT_BROADCAST = 23232 ) -type TCPNetwork struct { - Peers map[string]int +type TCP struct { DialTimeout time.Duration GetTimeout time.Duration + lock sync.RWMutex + peers map[string]int } -func NewTCPNetwork(peers ...string) *TCPNetwork { - t := &TCPNetwork{ - Peers: make(map[string]int), +func NewTCP(peers ...string) *TCP { + t := &TCP{ DialTimeout: TIMEOUT, GetTimeout: TIMEOUT, + peers: make(map[string]int), } for _, p := range peers { - t.AddPeer(p) + t.peers[p] = 0 } return t } -func (t *TCPNetwork) AddPeer(peer string) { - t.Peers[peer] = 0 +func (t *TCP) AddPeer(peer string) { + t.lock.Lock() + defer t.lock.Unlock() + t.ensurePeerMap() + t.peers[peer] = 0 } -func (t *TCPNetwork) SetPeers(peers ...string) { +func (t *TCP) SetPeers(peers ...string) { + t.lock.Lock() + defer t.lock.Unlock() ps := make(map[string]int, len(peers)) - // Copy errors into new map - for _, p := range peers { - e, ok := t.Peers[p] - if !ok { - e = 0 + if t.peers != nil { + // Copy errors into new map + for _, p := range peers { + e, ok := t.peers[p] + if !ok { + e = 0 + } + ps[p] = e } - ps[p] = e } - t.Peers = ps + t.peers = ps } -func (t *TCPNetwork) Connect(peer string, data []byte) error { +func (t *TCP) Connect(peer string, data []byte) error { address := net.JoinHostPort(peer, strconv.Itoa(PORT_CONNECT)) dialer := &net.Dialer{Timeout: t.DialTimeout} connection, err := dialer.Dial("tcp", address) @@ -92,9 +102,9 @@ func (t *TCPNetwork) Connect(peer string, data []byte) error { return nil } -func (t *TCPNetwork) GetHead(channel string) (*Reference, error) { - for _, peer := range t.peers() { - fmt.Println("Requesting", channel, "from", peer) +func (t *TCP) Head(channel string) (*bcgo.Reference, error) { + for _, peer := range t.bestPeers() { + log.Println("Requesting", channel, "from", peer) address := net.JoinHostPort(peer, strconv.Itoa(PORT_GET_HEAD)) dialer := &net.Dialer{Timeout: t.DialTimeout} connection, err := dialer.Dial("tcp", address) @@ -104,30 +114,30 @@ func (t *TCPNetwork) GetHead(channel string) (*Reference, error) { } defer connection.Close() writer := bufio.NewWriter(connection) - if err := WriteDelimitedProtobuf(writer, &Reference{ + if err := bcgo.WriteDelimitedProtobuf(writer, &bcgo.Reference{ ChannelName: channel, }); err != nil { t.error(peer, err) continue } reader := bufio.NewReader(connection) - reference := &Reference{} - if err := ReadDelimitedProtobuf(reader, reference); err != nil { + reference := &bcgo.Reference{} + if err := bcgo.ReadDelimitedProtobuf(reader, reference); err != nil { if err != io.EOF { t.error(peer, err) } continue } else { - fmt.Println("Received", TimestampToString(reference.Timestamp), reference.ChannelName, base64.RawURLEncoding.EncodeToString(reference.BlockHash), "from", peer) + log.Println("Received", bcgo.TimestampToString(reference.Timestamp), reference.ChannelName, base64.RawURLEncoding.EncodeToString(reference.BlockHash), "from", peer) return reference, nil } } return nil, fmt.Errorf("Could not get %s from peers", channel) } -func (t *TCPNetwork) GetBlock(reference *Reference) (*Block, error) { - for _, peer := range t.peers() { - fmt.Println("Requesting", reference.ChannelName, base64.RawURLEncoding.EncodeToString(reference.BlockHash), base64.RawURLEncoding.EncodeToString(reference.RecordHash), "from", peer) +func (t *TCP) Block(reference *bcgo.Reference) (*bcgo.Block, error) { + for _, peer := range t.bestPeers() { + log.Println("Requesting", reference.ChannelName, base64.RawURLEncoding.EncodeToString(reference.BlockHash), base64.RawURLEncoding.EncodeToString(reference.RecordHash), "from", peer) address := net.JoinHostPort(peer, strconv.Itoa(PORT_GET_BLOCK)) dialer := &net.Dialer{Timeout: t.DialTimeout} connection, err := dialer.Dial("tcp", address) @@ -137,30 +147,30 @@ func (t *TCPNetwork) GetBlock(reference *Reference) (*Block, error) { } defer connection.Close() writer := bufio.NewWriter(connection) - if err := WriteDelimitedProtobuf(writer, reference); err != nil { + if err := bcgo.WriteDelimitedProtobuf(writer, reference); err != nil { t.error(peer, err) continue } reader := bufio.NewReader(connection) - block := &Block{} - if err := ReadDelimitedProtobuf(reader, block); err != nil { + block := &bcgo.Block{} + if err := bcgo.ReadDelimitedProtobuf(reader, block); err != nil { if err != io.EOF { t.error(peer, err) } continue } else { - fmt.Println("Received", TimestampToString(block.Timestamp), block.ChannelName, "from", peer) + log.Println("Received", bcgo.TimestampToString(block.Timestamp), block.ChannelName, "from", peer) return block, nil } } return nil, fmt.Errorf("Could not get %s block from peers", reference.ChannelName) } -func (t *TCPNetwork) Broadcast(channel *Channel, cache Cache, hash []byte, block *Block) error { +func (t *TCP) Broadcast(channel bcgo.Channel, cache bcgo.Cache, hash []byte, block *bcgo.Block) error { var last error - for _, peer := range t.peers() { + for _, peer := range t.bestPeers() { last = nil - fmt.Println("Broadcasting", channel, base64.RawURLEncoding.EncodeToString(hash), "to", peer) + log.Println("Broadcasting", channel, base64.RawURLEncoding.EncodeToString(hash), "to", peer) address := net.JoinHostPort(peer, strconv.Itoa(PORT_BROADCAST)) dialer := &net.Dialer{Timeout: t.DialTimeout} connection, err := dialer.Dial("tcp", address) @@ -174,11 +184,11 @@ func (t *TCPNetwork) Broadcast(channel *Channel, cache Cache, hash []byte, block reader := bufio.NewReader(connection) for { - if err := WriteDelimitedProtobuf(writer, block); err != nil { + if err := bcgo.WriteDelimitedProtobuf(writer, block); err != nil { return err } - reference := &Reference{} - if err := ReadDelimitedProtobuf(reader, reference); err != nil { + reference := &bcgo.Reference{} + if err := bcgo.ReadDelimitedProtobuf(reader, reference); err != nil { if err == io.EOF { // Ignore break @@ -189,32 +199,32 @@ func (t *TCPNetwork) Broadcast(channel *Channel, cache Cache, hash []byte, block remote := reference.BlockHash if bytes.Equal(hash, remote) { // Broadcast accepted - fmt.Println("Broadcast to", peer, "succeeded") + log.Println("Broadcast to", peer, "succeeded") break } else { // Broadcast rejected - referencedBlock, err := GetBlock(channel.Name, cache, t, remote) + referencedBlock, err := bcgo.LoadBlock(channel.Name(), cache, t, remote) if err != nil { return err } if referencedBlock.Length == block.Length { // Option A: remote points to a different chain of the same length, next chain to get a block mined on top wins - fmt.Println("Broadcast to", peer, "failed: Option A") + log.Println("Broadcast to", peer, "failed: Option A") break } else if referencedBlock.Length > block.Length { // Option B: remote points to a longer chain - fmt.Println("Broadcast to", peer, "failed: Option B") + log.Println("Broadcast to", peer, "failed: Option B") go func() { if err := channel.Pull(cache, t); err != nil { - fmt.Println(err) + log.Println(err) } }() - return errors.New(ERROR_CHANNEL_OUT_OF_DATE) + return bcgo.ErrChannelOutOfDate{Channel: channel.Name()} // TODO re-mine all dropped records into new blocks on top of new head } else { // Option C: remote points to a shorter chain, and cannot update because the chain cannot be verified or the host is missing some blocks - fmt.Println("Broadcast to", peer, "failed: Option C") + log.Println("Broadcast to", peer, "failed: Option C") block = referencedBlock } } @@ -223,30 +233,80 @@ func (t *TCPNetwork) Broadcast(channel *Channel, cache Cache, hash []byte, block return last } -// Returns a slice of peers sorted by ascending error rate -func (t *TCPNetwork) peers() []string { - var peers []string - for p := range t.Peers { - if len(p) == 0 { - continue +// Returns the peer associated with the given address +func (t *TCP) PeerForAddress(address string) string { + host, _, err := net.SplitHostPort(address) + if err != nil { + log.Println(address, err) + return "" + } + hIP := net.ParseIP(host) + peers := t.Peers() + for _, p := range peers { + if p == host { + return p + } + if hIP != nil { + // DNS lookup peer to get IP addresses + ips, err := net.LookupIP(p) + if err != nil { + continue + } + for _, ip := range ips { + if ip.Equal(hIP) { + return p + } + } } - peers = append(peers, p) } + return "" +} + +func (t *TCP) Peers() (peers []string) { + t.lock.RLock() + defer t.lock.RUnlock() + if t.peers != nil { + for p := range t.peers { + if p == "" { + continue + } + peers = append(peers, p) + } + } + return +} + +// Returns a slice of peers sorted by ascending error rate +func (t *TCP) bestPeers() []string { + peers := t.Peers() if len(peers) == 0 { return peers } - sort.Slice(peers, func(i, j int) bool { - return t.Peers[peers[i]] < t.Peers[peers[j]] - }) + if t.peers != nil { + t.lock.RLock() + sort.Slice(peers, func(i, j int) bool { + return t.peers[peers[i]] < t.peers[peers[j]] + }) + t.lock.RUnlock() + } return peers[:1+len(peers)/2] // return first half of peers ie least erroneous } -func (t *TCPNetwork) error(peer string, err error) { - fmt.Println("Error:", peer, err) - count := t.Peers[peer] + 1 - t.Peers[peer] = count +func (t *TCP) ensurePeerMap() { + if t.peers == nil { + t.peers = make(map[string]int) + } +} + +func (t *TCP) error(peer string, err error) { + t.lock.Lock() + defer t.lock.Unlock() + log.Println("Error:", peer, err) + t.ensurePeerMap() + count := t.peers[peer] + 1 + t.peers[peer] = count if count > MAX_TCP_ERRORS { - fmt.Println(peer, "Exceeded MAX_TCP_ERRORS") - delete(t.Peers, peer) + log.Println(peer, "Exceeded MAX_TCP_ERRORS") + delete(t.peers, peer) } } diff --git a/vendor/aletheiaware.com/bcgo/node.go b/vendor/aletheiaware.com/bcgo/node.go index 390bfdf..c8159c1 100644 --- a/vendor/aletheiaware.com/bcgo/node.go +++ b/vendor/aletheiaware.com/bcgo/node.go @@ -1,5 +1,5 @@ /* - * Copyright 2019 Aletheia Ware LLC + * Copyright 2019-21 Aletheia Ware LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,234 +16,13 @@ package bcgo -import ( - "aletheiaware.com/cryptogo" - "crypto/rsa" - "errors" - "fmt" - "github.com/golang/protobuf/proto" - "sort" -) - -const ( - ERROR_NO_ENTRIES_TO_MINE = "No entries to mine for channel: %s" - ERROR_NO_SUCH_CHANNEL = "No such channel: %s" - ERROR_PAYLOAD_TOO_LARGE = "Payload too large: %s max: %s" - ERROR_BLOCK_TOO_LARGE = "Block too large: %s max: %s" - ERROR_NONCE_WRAP_AROUND = "Nonce wrapped around before reaching threshold" -) - -type MiningListener interface { - OnMiningStarted(channel *Channel, size uint64) - OnNewMaxOnes(channel *Channel, nonce, ones uint64) - OnMiningThresholdReached(channel *Channel, hash []byte, block *Block) -} - -type Node struct { - Alias string - Key *rsa.PrivateKey - Cache Cache - Network Network - Channels map[string]*Channel -} - -func NewNode(directory string, cache Cache, network Network) (*Node, error) { - // Get alias - alias, err := GetAlias() - if err != nil { - return nil, err - } - keystore, err := GetKeyDirectory(directory) - if err != nil { - return nil, err - } - // Get private key - key, err := cryptogo.GetOrCreateRSAPrivateKey(keystore, alias) - if err != nil { - return nil, err - } - return &Node{ - Alias: alias, - Key: key, - Cache: cache, - Network: network, - Channels: make(map[string]*Channel), - }, nil -} - -func (n *Node) AddChannel(channel *Channel) { - n.Channels[channel.Name] = channel -} - -func (n *Node) GetChannel(name string) (*Channel, error) { - c, ok := n.Channels[name] - if !ok { - return nil, fmt.Errorf(ERROR_NO_SUCH_CHANNEL, name) - } - return c, nil -} - -func (n *Node) GetOrOpenChannel(name string, opener func() *Channel) *Channel { - c, ok := n.Channels[name] - if !ok { - c = opener() - if c != nil { - if err := c.LoadCachedHead(n.Cache); err != nil { - // Ignored - } - n.AddChannel(c) - } - } - return c -} - -func (n *Node) GetChannels() []*Channel { - var keys []string - for k := range n.Channels { - keys = append(keys, k) - } - sort.Strings(keys) - - var channels []*Channel - for _, k := range keys { - channels = append(channels, n.Channels[k]) - } - return channels -} - -func (n *Node) Write(timestamp uint64, channel *Channel, acl map[string]*rsa.PublicKey, references []*Reference, payload []byte) (*Reference, error) { - size := uint64(len(payload)) - if size > MAX_PAYLOAD_SIZE_BYTES { - return nil, fmt.Errorf(ERROR_PAYLOAD_TOO_LARGE, BinarySizeToString(size), BinarySizeToString(MAX_PAYLOAD_SIZE_BYTES)) - } - _, record, err := CreateRecord(timestamp, n.Alias, n.Key, acl, references, payload) - if err != nil { - return nil, err - } - return WriteRecord(channel.Name, n.Cache, record) -} - -func (n *Node) MineProto(channel *Channel, threshold uint64, listener MiningListener, acl map[string]*rsa.PublicKey, references []*Reference, message proto.Message) error { - data, err := proto.Marshal(message) - if err != nil { - return err - } - - if _, err := n.Write(Timestamp(), channel, acl, references, data); err != nil { - return err - } - - if _, _, err := n.Mine(channel, threshold, listener); err != nil { - return err - } - - if err := channel.Push(n.Cache, n.Network); err != nil { - return err - } - return nil -} - -func (n *Node) GetLastMinedTimestamp(channel *Channel) (uint64, error) { - var timestamp uint64 - // Iterate through the chain to find the most recent block mined by this node - if err := Iterate(channel.Name, channel.Head, nil, n.Cache, n.Network, func(h []byte, b *Block) error { - if b.Miner == n.Alias { - timestamp = b.Timestamp - return StopIterationError{} - } - return nil - }); err != nil { - switch err.(type) { - case StopIterationError: - // Do nothing - break - default: - return 0, err - } - } - return timestamp, nil -} - -func (n *Node) Mine(channel *Channel, threshold uint64, listener MiningListener) ([]byte, *Block, error) { - timestamp, err := n.GetLastMinedTimestamp(channel) - if err != nil { - return nil, nil, err - } - - entries, err := n.Cache.GetBlockEntries(channel.Name, timestamp) - if err != nil { - return nil, nil, err - } - - // Sort by timestamp - sort.Slice(entries, func(i, j int) bool { - return entries[i].Record.Timestamp < entries[j].Record.Timestamp - }) - - return n.MineEntries(channel, threshold, listener, entries) -} - -func (n *Node) MineEntries(channel *Channel, threshold uint64, listener MiningListener, entries []*BlockEntry) ([]byte, *Block, error) { - if len(entries) == 0 { - return nil, nil, fmt.Errorf(ERROR_NO_ENTRIES_TO_MINE, channel.Name) - } - - // TODO check record signature of each entry - - block := &Block{ - Timestamp: Timestamp(), - ChannelName: channel.Name, - Length: 1, - Miner: n.Alias, - Entry: entries, - } - - previousHash := channel.Head - if previousHash != nil { - previousBlock, err := n.Cache.GetBlock(previousHash) - if err != nil { - return nil, nil, err - } - block.Length = previousBlock.Length + 1 - block.Previous = previousHash - } - - return n.MineBlock(channel, threshold, listener, block) -} - -func (n *Node) MineBlock(channel *Channel, threshold uint64, listener MiningListener, block *Block) ([]byte, *Block, error) { - size := uint64(proto.Size(block)) - if size > MAX_BLOCK_SIZE_BYTES { - return nil, nil, fmt.Errorf(ERROR_BLOCK_TOO_LARGE, BinarySizeToString(size), BinarySizeToString(MAX_BLOCK_SIZE_BYTES)) - } - - if listener != nil { - listener.OnMiningStarted(channel, size) - } - - var max uint64 - for nonce := uint64(1); nonce > 0; nonce++ { - block.Nonce = nonce - hash, err := cryptogo.HashProtobuf(block) - if err != nil { - return nil, nil, err - } - ones := Ones(hash) - if ones > max { - if listener != nil { - listener.OnNewMaxOnes(channel, nonce, ones) - } - max = ones - } - if ones > threshold { - if listener != nil { - listener.OnMiningThresholdReached(channel, hash, block) - } - if err := channel.Update(n.Cache, n.Network, hash, block); err != nil { - return nil, nil, err - } - return hash, block, nil - } - } - return nil, nil, errors.New(ERROR_NONCE_WRAP_AROUND) +type Node interface { + Account() Account + Cache() Cache + Network() Network + AddChannel(Channel) + Channel(string) (Channel, error) + OpenChannel(string, func() Channel) Channel + Channels() []Channel + Write(uint64, Channel, []Identity, []*Reference, []byte) (*Reference, error) } diff --git a/vendor/aletheiaware.com/bcgo/node/node.go b/vendor/aletheiaware.com/bcgo/node/node.go new file mode 100644 index 0000000..98355fe --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/node/node.go @@ -0,0 +1,112 @@ +/* + * Copyright 2019-21 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package node + +import ( + "aletheiaware.com/bcgo" + "sort" + "sync" +) + +type node struct { + account bcgo.Account + cache bcgo.Cache + network bcgo.Network + channels map[string]bcgo.Channel + lock sync.Mutex +} + +func New(account bcgo.Account, cache bcgo.Cache, network bcgo.Network) bcgo.Node { + return &node{ + account: account, + cache: cache, + network: network, + channels: make(map[string]bcgo.Channel), + } +} + +func (n *node) Account() bcgo.Account { + return n.account +} + +func (n *node) Cache() bcgo.Cache { + return n.cache +} + +func (n *node) Network() bcgo.Network { + return n.network +} + +func (n *node) AddChannel(channel bcgo.Channel) { + n.lock.Lock() + defer n.lock.Unlock() + n.channels[channel.Name()] = channel +} + +func (n *node) Channel(name string) (bcgo.Channel, error) { + n.lock.Lock() + defer n.lock.Unlock() + c, ok := n.channels[name] + if !ok { + return nil, bcgo.ErrNoSuchChannel{Channel: name} + } + return c, nil +} + +func (n *node) OpenChannel(name string, opener func() bcgo.Channel) bcgo.Channel { + n.lock.Lock() + c, ok := n.channels[name] + n.lock.Unlock() + if !ok { + c = opener() + if c != nil { + if err := c.Load(n.cache, nil); err != nil { + // Ignored + } + n.AddChannel(c) + } + } + return c +} + +func (n *node) Channels() []bcgo.Channel { + n.lock.Lock() + defer n.lock.Unlock() + var keys []string + for k := range n.channels { + keys = append(keys, k) + } + sort.Strings(keys) + + var channels []bcgo.Channel + for _, k := range keys { + channels = append(channels, n.channels[k]) + } + return channels +} + +func (n *node) Write(timestamp uint64, channel bcgo.Channel, access []bcgo.Identity, references []*bcgo.Reference, payload []byte) (*bcgo.Reference, error) { + size := uint64(len(payload)) + if size > bcgo.MAX_PAYLOAD_SIZE_BYTES { + return nil, bcgo.ErrPayloadTooLarge{Size: size, Max: bcgo.MAX_PAYLOAD_SIZE_BYTES} + } + _, record, err := bcgo.CreateRecord(timestamp, n.account, access, references, payload) + if err != nil { + return nil, err + } + return bcgo.WriteRecord(channel.Name(), n.cache, record) +} diff --git a/vendor/aletheiaware.com/bcgo/periodicvalidation.go b/vendor/aletheiaware.com/bcgo/periodicvalidation.go deleted file mode 100644 index 86503c6..0000000 --- a/vendor/aletheiaware.com/bcgo/periodicvalidation.go +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright 2019 Aletheia Ware LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package bcgo - -import ( - "aletheiaware.com/cryptogo" - "encoding/base64" - "fmt" - "github.com/golang/protobuf/proto" - "log" - "strings" - "time" -) - -// Periodic Validation Chains strengthen the Network by increasing the computational resources needed to attack it. - -const ( - ERROR_MISSING_VALIDATED_BLOCK = "Missing Validated Block %s" - - PERIOD_HOURLY = time.Hour - PERIOD_DAILY = PERIOD_HOURLY * 24 - PERIOD_WEEKLY = PERIOD_HOURLY * 168 // (24 * 7) - PERIOD_YEARLY = PERIOD_HOURLY * 8766 // (24 * 365.25) - PERIOD_DECENNIALLY = PERIOD_HOURLY * 87660 // (24 * 365.25 * 10) - PERIOD_CENTENNIALLY = PERIOD_HOURLY * 876600 // (24 * 365.25 * 100) - - THRESHOLD_PERIOD_HOUR = THRESHOLD_F - THRESHOLD_PERIOD_DAY = THRESHOLD_E - THRESHOLD_PERIOD_WEEK = THRESHOLD_D - THRESHOLD_PERIOD_YEAR = THRESHOLD_C - THRESHOLD_PERIOD_DECADE = THRESHOLD_B - THRESHOLD_PERIOD_CENTURY = THRESHOLD_A -) - -type PeriodicValidator struct { - // TODO add validator that each block holds the full channel set of the previous - // TODO add validator that the duration between block timestamps equals or exceeds the period - // TODO add validator that each head reference in block is the longest chain before timestamp - Channel *Channel - Period time.Duration - Ticker *time.Ticker -} - -func NewPeriodicValidator(channel *Channel, period time.Duration) *PeriodicValidator { - return &PeriodicValidator{ - Channel: channel, - Period: period, - } -} - -func GetHourlyValidator(channel *Channel) *PeriodicValidator { - return NewPeriodicValidator(channel, PERIOD_HOURLY) -} - -func GetDailyValidator(channel *Channel) *PeriodicValidator { - return NewPeriodicValidator(channel, PERIOD_DAILY) -} - -func GetWeeklyValidator(channel *Channel) *PeriodicValidator { - return NewPeriodicValidator(channel, PERIOD_WEEKLY) -} - -func GetYearlyValidator(channel *Channel) *PeriodicValidator { - return NewPeriodicValidator(channel, PERIOD_YEARLY) -} - -func GetDecenniallyValidator(channel *Channel) *PeriodicValidator { - return NewPeriodicValidator(channel, PERIOD_DECENNIALLY) -} - -func GetCentenniallyValidator(channel *Channel) *PeriodicValidator { - return NewPeriodicValidator(channel, PERIOD_CENTENNIALLY) -} - -// Fills the given set with the names of all channels validated in this chain -func (p *PeriodicValidator) FillChannelSet(set map[string]bool, cache Cache, network Network) error { - return Iterate(p.Channel.Name, p.Channel.Head, nil, cache, network, func(h []byte, b *Block) error { - for _, entry := range b.Entry { - // Unmarshal as Reference - r := &Reference{} - err := proto.Unmarshal(entry.Record.Payload, r) - if err != nil { - return err - } - set[r.ChannelName] = true - } - return nil - }) -} - -// Ensures all block hashes in validation chain for given channel appear in its chain -func (p *PeriodicValidator) Validate(channel *Channel, cache Cache, network Network, hash []byte, block *Block) error { - // Mark all block hashes for channel in p.Channel - set := make(map[string]bool) - if err := Iterate(p.Channel.Name, p.Channel.Head, nil, cache, network, func(h []byte, b *Block) error { - for _, entry := range b.Entry { - // Unmarshal as Reference - r := &Reference{} - err := proto.Unmarshal(entry.Record.Payload, r) - if err != nil { - return err - } - if r.ChannelName == channel.Name { - set[base64.RawURLEncoding.EncodeToString(r.BlockHash)] = true - } - } - return nil - }); err != nil { - return err - } - - // Unmark all block hashes which appear is chain - if err := Iterate(channel.Name, hash, block, cache, network, func(h []byte, b *Block) error { - set[base64.RawURLEncoding.EncodeToString(h)] = false - return nil - }); err != nil { - return err - } - - // Collect all marked block hashes - var missing []string - for hash, marked := range set { - if marked { - missing = append(missing, hash) - } - } - if len(missing) > 0 { - return fmt.Errorf(ERROR_MISSING_VALIDATED_BLOCK, strings.Join(missing, ",")) - } - return nil -} - -func (p *PeriodicValidator) Update(node *Node, threshold uint64, listener MiningListener, timestamp uint64) error { - entries, err := CreateValidationEntries(timestamp, node) - if err != nil { - return err - } - name := p.Channel.Name - head := p.Channel.Head - var block *Block - if head != nil { - block, err = GetBlock(name, node.Cache, node.Network, head) - if err != nil { - return err - } - } - b := CreateValidationBlock(timestamp, name, node.Alias, head, block, entries) - _, _, err = node.MineBlock(p.Channel, threshold, listener, b) - if err != nil { - return err - } - return nil -} - -// Periodically mines a new block into the chain containing the head hashes of all open channels -func (p *PeriodicValidator) Start(node *Node, threshold uint64, listener MiningListener) { - // 3 times per period - p.Ticker = time.NewTicker(p.Period / 3) - c := p.Ticker.C - for { - go func() { - for { - now := time.Now().UTC() - last := int64(p.Channel.Timestamp) - next := time.Unix(0, last).Add(p.Period) - var timestamp uint64 - if last == 0 { - timestamp = uint64(now.UnixNano()) - } else if now.After(next) { - timestamp = uint64(next.UnixNano()) - } else { - break - } - if err := p.Update(node, threshold, listener, timestamp); err != nil { - log.Println(err) - p.Stop() - break - } - if err := p.Channel.Push(node.Cache, node.Network); err != nil { - log.Println(err) - } - } - }() - if _, ok := <-c; !ok { - return - } - } -} - -func (p *PeriodicValidator) Stop() { - if p.Ticker != nil { - p.Ticker.Stop() - p.Ticker = nil - } -} - -func CreateValidationBlock(timestamp uint64, channel, alias string, head []byte, block *Block, entries []*BlockEntry) *Block { - b := &Block{ - Timestamp: timestamp, - ChannelName: channel, - Length: 1, - Miner: alias, - Entry: entries, - } - - if head != nil && block != nil { - b.Length = block.Length + 1 - b.Previous = head - } - - return b -} - -func CreateValidationEntries(timestamp uint64, node *Node) ([]*BlockEntry, error) { - var entries []*BlockEntry - for _, channel := range node.GetChannels() { - head := channel.Head - updated := channel.Timestamp - if updated > timestamp { - // Channel was updated after Validation Cycle started - head = nil - // Iterate back through channel blocks until block.Timestamp <= timestamp - if err := Iterate(channel.Name, channel.Head, nil, node.Cache, node.Network, func(h []byte, b *Block) error { - if b.Timestamp <= timestamp { - head = h - updated = b.Timestamp - return StopIterationError{} - } - return nil - }); err != nil { - switch err.(type) { - case StopIterationError: - // Do nothing - default: - return nil, err - } - } - } - if head == nil { - continue - } - entry, err := CreateValidationEntry(timestamp, node, channel.Name, updated, head) - if err != nil { - return nil, err - } - entries = append(entries, entry) - } - return entries, nil -} - -func CreateValidationEntry(timestamp uint64, node *Node, channel string, updated uint64, head []byte) (*BlockEntry, error) { - reference := &Reference{ - Timestamp: updated, - ChannelName: channel, - BlockHash: head, - } - payload, err := proto.Marshal(reference) - if err != nil { - return nil, err - } - _, record, err := CreateRecord(timestamp, node.Alias, node.Key, nil, nil, payload) - if err != nil { - return nil, err - } - hash, err := cryptogo.HashProtobuf(record) - if err != nil { - return nil, err - } - return &BlockEntry{ - RecordHash: hash, - Record: record, - }, nil -} diff --git a/vendor/aletheiaware.com/bcgo/powvalidation.go b/vendor/aletheiaware.com/bcgo/powvalidation.go deleted file mode 100644 index e42fa4b..0000000 --- a/vendor/aletheiaware.com/bcgo/powvalidation.go +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2019 Aletheia Ware LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package bcgo - -import ( - "fmt" -) - -const ( - ERROR_HASH_TOO_WEAK = "Hash doesn't meet Proof-of-Work threshold: %d vs %d" -) - -func OpenPoWChannel(name string, threshold uint64) *Channel { - return &Channel{ - Name: name, - Validators: []Validator{ - &PoWValidator{ - Threshold: threshold, - }, - }, - } -} - -type PoWValidator struct { - Threshold uint64 -} - -func (p *PoWValidator) Validate(channel *Channel, cache Cache, network Network, hash []byte, block *Block) error { - return Iterate(channel.Name, hash, block, cache, network, func(h []byte, b *Block) error { - // Check hash ones pass threshold - ones := Ones(h) - if ones < p.Threshold { - return fmt.Errorf(ERROR_HASH_TOO_WEAK, ones, p.Threshold) - } - return nil - }) -} diff --git a/vendor/aletheiaware.com/bcgo/printer.go b/vendor/aletheiaware.com/bcgo/printer.go index 8565307..7220346 100644 --- a/vendor/aletheiaware.com/bcgo/printer.go +++ b/vendor/aletheiaware.com/bcgo/printer.go @@ -26,16 +26,16 @@ type PrintingMiningListener struct { Output io.Writer } -func (p *PrintingMiningListener) OnMiningStarted(channel *Channel, size uint64) { - fmt.Fprintf(p.Output, "Mining %s %s\n", channel.Name, BinarySizeToString(size)) +func (p *PrintingMiningListener) OnMiningStarted(channel Channel, size uint64) { + fmt.Fprintf(p.Output, "Mining %s %s\n", channel.Name(), BinarySizeToString(size)) } -func (p *PrintingMiningListener) OnNewMaxOnes(channel *Channel, nonce, ones uint64) { - fmt.Fprintf(p.Output, "Mining %s %d %d/512\n", channel.Name, nonce, ones) +func (p *PrintingMiningListener) OnNewMaxOnes(channel Channel, nonce, ones uint64) { + fmt.Fprintf(p.Output, "Mining %s %d %d/512\n", channel.Name(), nonce, ones) } -func (p *PrintingMiningListener) OnMiningThresholdReached(channel *Channel, hash []byte, block *Block) { - fmt.Fprintf(p.Output, "Mined %s %s %s\n", channel.Name, TimestampToString(block.Timestamp), base64.RawURLEncoding.EncodeToString(hash)) +func (p *PrintingMiningListener) OnMiningThresholdReached(channel Channel, hash []byte, block *Block) { + fmt.Fprintf(p.Output, "Mined %s %s %s\n", channel.Name(), TimestampToString(block.Timestamp), base64.RawURLEncoding.EncodeToString(hash)) } /* diff --git a/vendor/aletheiaware.com/bcgo/validation.go b/vendor/aletheiaware.com/bcgo/validation.go index b8a0a60..7c25129 100644 --- a/vendor/aletheiaware.com/bcgo/validation.go +++ b/vendor/aletheiaware.com/bcgo/validation.go @@ -17,5 +17,5 @@ package bcgo type Validator interface { - Validate(channel *Channel, cache Cache, network Network, hash []byte, block *Block) error + Validate(channel Channel, cache Cache, network Network, hash []byte, block *Block) error } diff --git a/vendor/aletheiaware.com/bcgo/validation/errors.go b/vendor/aletheiaware.com/bcgo/validation/errors.go new file mode 100644 index 0000000..8c258bb --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/validation/errors.go @@ -0,0 +1,68 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package validation + +import ( + "fmt" + "strings" +) + +// ErrDifferentLiveFlag is returned when a block's live flag doesn't match the current setting. +type ErrDifferentLiveFlag struct { + Expected, Actual string +} + +func (e ErrDifferentLiveFlag) Error() string { + return fmt.Sprintf("Different Live Flag; Expected '%s', got '%s'", e.Expected, e.Actual) +} + +// ErrDuplicateBlock is returned when a block appears multiple times in a chain. +type ErrDuplicateBlock struct { + Hash string +} + +func (e ErrDuplicateBlock) Error() string { + return fmt.Sprintf("Duplicate Block: %s", e.Hash) +} + +// ErrDuplicateEntry is returned when an entry appears multiple times in a chain. +type ErrDuplicateEntry struct { + Hash string +} + +func (e ErrDuplicateEntry) Error() string { + return fmt.Sprintf("Duplicate Entry: %s", e.Hash) +} + +// ErrHashTooWeak is returned when a block's hash doesn't meet the threshold. +type ErrHashTooWeak struct { + Expected, Actual uint64 +} + +func (e ErrHashTooWeak) Error() string { + return fmt.Sprintf("Hash doesn't meet Proof-of-Work threshold: %d vs %d", e.Expected, e.Actual) +} + +// ErrMissingValidatedBlock is returned when a chain doesn't contain a block recorded in periodic validation chain. +type ErrMissingValidatedBlock struct { + PVC, Channel string + Missing []string +} + +func (e ErrMissingValidatedBlock) Error() string { + return fmt.Sprintf("%s Missing Validated Block %s %s", e.PVC, e.Channel, strings.Join(e.Missing, ",")) +} diff --git a/vendor/aletheiaware.com/bcgo/livevalidation.go b/vendor/aletheiaware.com/bcgo/validation/live.go similarity index 58% rename from vendor/aletheiaware.com/bcgo/livevalidation.go rename to vendor/aletheiaware.com/bcgo/validation/live.go index 42f6938..aa2a778 100644 --- a/vendor/aletheiaware.com/bcgo/livevalidation.go +++ b/vendor/aletheiaware.com/bcgo/validation/live.go @@ -1,5 +1,5 @@ /* - * Copyright 2020 Aletheia Ware LLC + * Copyright 2020-21 Aletheia Ware LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,33 +14,28 @@ * limitations under the License. */ -package bcgo +package validation import ( - "fmt" + "aletheiaware.com/bcgo" "os" ) -// Live Validation ensures the Live flag in each Records' Metadata matches the Live environment variable. - -const ( - ERROR_DIFFERENT_LIVE_FLAG = "Different Live Flag; Expected '%s', got '%s'" -) - -type LiveValidator struct { +// Live is a validator which ensures the Live flag in each Records' Metadata matches the Live environment variable. +type Live struct { } // Validate ensures all records have a live flag in their metadata which matches the environment variable. -func (p *LiveValidator) Validate(channel *Channel, cache Cache, network Network, hash []byte, block *Block) error { - expected := os.Getenv(LIVE_FLAG) - return Iterate(channel.Name, hash, block, cache, network, func(h []byte, b *Block) error { +func (v *Live) Validate(channel bcgo.Channel, cache bcgo.Cache, network bcgo.Network, hash []byte, block *bcgo.Block) error { + expected := os.Getenv(bcgo.LIVE_FLAG) + return bcgo.Iterate(channel.Name(), hash, block, cache, network, func(h []byte, b *bcgo.Block) error { for _, entry := range b.Entry { var flag string if meta := entry.Record.Meta; meta != nil { - flag = meta[LIVE_FLAG] + flag = meta[bcgo.LIVE_FLAG] } if flag != expected { - return fmt.Errorf(ERROR_DIFFERENT_LIVE_FLAG, expected, flag) + return ErrDifferentLiveFlag{Expected: expected, Actual: flag} } } return nil diff --git a/vendor/aletheiaware.com/bcgo/validation/periodic.go b/vendor/aletheiaware.com/bcgo/validation/periodic.go new file mode 100644 index 0000000..79ae4c4 --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/validation/periodic.go @@ -0,0 +1,351 @@ +/* + * Copyright 2019-21 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package validation + +import ( + "aletheiaware.com/bcgo" + "aletheiaware.com/cryptogo" + "encoding/base64" + "github.com/golang/protobuf/proto" + "log" + "time" +) + +// Periodic Validation Chains strengthen the Network by increasing the computational resources needed to attack it. + +const ( + PERIOD_HOURLY = time.Hour + PERIOD_DAILY = PERIOD_HOURLY * 24 + PERIOD_WEEKLY = PERIOD_HOURLY * 168 // (24 * 7) + PERIOD_YEARLY = PERIOD_HOURLY * 8766 // (24 * 365.25) + PERIOD_DECENNIALLY = PERIOD_HOURLY * 87660 // (24 * 365.25 * 10) + PERIOD_CENTENNIALLY = PERIOD_HOURLY * 876600 // (24 * 365.25 * 100) + + THRESHOLD_PERIOD_HOUR = bcgo.THRESHOLD_F + THRESHOLD_PERIOD_DAY = bcgo.THRESHOLD_E + THRESHOLD_PERIOD_WEEK = bcgo.THRESHOLD_D + THRESHOLD_PERIOD_YEAR = bcgo.THRESHOLD_C + THRESHOLD_PERIOD_DECADE = bcgo.THRESHOLD_B + THRESHOLD_PERIOD_CENTURY = bcgo.THRESHOLD_A +) + +type Periodic interface { + bcgo.Validator + AddChannel(string) + FillChannelSet(map[string]bool, bcgo.Cache, bcgo.Network) error + Update(bcgo.Cache, bcgo.Network, uint64) error + Start() + Stop() +} + +type periodic struct { + // TODO add validator that each block holds the full channel set of the previous + // TODO add validator that the duration between block timestamps equals or exceeds the period + // TODO add validator that each head reference in block is the longest chain before timestamp + Node bcgo.Node + Channel bcgo.Channel + Threshold uint64 + Listener bcgo.MiningListener + Period time.Duration + Ticker *time.Ticker + Channels map[string]bool +} + +func NewPeriodic(node bcgo.Node, channel bcgo.Channel, threshold uint64, listener bcgo.MiningListener, period time.Duration) Periodic { + p := &periodic{ + Node: node, + Channel: channel, + Threshold: threshold, + Listener: listener, + Period: period, + Channels: make(map[string]bool), + } + p.Channel.AddTrigger(p.updateValidatedChannels) + return p +} + +func NewHourly(node bcgo.Node, channel bcgo.Channel, listener bcgo.MiningListener) Periodic { + return NewPeriodic(node, channel, bcgo.THRESHOLD_F, listener, PERIOD_HOURLY) +} + +func NewDaily(node bcgo.Node, channel bcgo.Channel, listener bcgo.MiningListener) Periodic { + return NewPeriodic(node, channel, bcgo.THRESHOLD_E, listener, PERIOD_DAILY) +} + +func NewWeekly(node bcgo.Node, channel bcgo.Channel, listener bcgo.MiningListener) Periodic { + return NewPeriodic(node, channel, bcgo.THRESHOLD_D, listener, PERIOD_WEEKLY) +} + +func NewYearly(node bcgo.Node, channel bcgo.Channel, listener bcgo.MiningListener) Periodic { + return NewPeriodic(node, channel, bcgo.THRESHOLD_C, listener, PERIOD_YEARLY) +} + +func NewDecennially(node bcgo.Node, channel bcgo.Channel, listener bcgo.MiningListener) Periodic { + return NewPeriodic(node, channel, bcgo.THRESHOLD_B, listener, PERIOD_DECENNIALLY) +} + +func NewCentennially(node bcgo.Node, channel bcgo.Channel, listener bcgo.MiningListener) Periodic { + return NewPeriodic(node, channel, bcgo.THRESHOLD_A, listener, PERIOD_CENTENNIALLY) +} + +func (p *periodic) AddChannel(channel string) { + p.Channels[channel] = true +} + +// Fills the given set with the names of all channels validated in this chain +func (p *periodic) FillChannelSet(set map[string]bool, cache bcgo.Cache, network bcgo.Network) error { + return bcgo.Iterate(p.Channel.Name(), p.Channel.Head(), nil, cache, network, func(h []byte, b *bcgo.Block) error { + for _, entry := range b.Entry { + // Unmarshal as Reference + r := &bcgo.Reference{} + err := proto.Unmarshal(entry.Record.Payload, r) + if err != nil { + return err + } + set[r.ChannelName] = true + } + return nil + }) +} + +// Ensures all block hashes in validation chain for given channel appear in its chain +func (p *periodic) Validate(channel bcgo.Channel, cache bcgo.Cache, network bcgo.Network, hash []byte, block *bcgo.Block) error { + name := channel.Name() + // Mark all block hashes for channel in p.Channel + set := make(map[string]bool) + if err := bcgo.Iterate(p.Channel.Name(), p.Channel.Head(), nil, cache, network, func(h []byte, b *bcgo.Block) error { + for _, entry := range b.Entry { + // Unmarshal as Reference + r := &bcgo.Reference{} + err := proto.Unmarshal(entry.Record.Payload, r) + if err != nil { + return err + } + if r.ChannelName == name { + set[base64.RawURLEncoding.EncodeToString(r.BlockHash)] = true + } + } + return nil + }); err != nil { + return err + } + + // Unmark all block hashes which appear is chain + if err := bcgo.Iterate(name, hash, block, cache, network, func(h []byte, b *bcgo.Block) error { + set[base64.RawURLEncoding.EncodeToString(h)] = false + return nil + }); err != nil { + return err + } + + // Collect all marked block hashes + var missing []string + for hash, marked := range set { + if marked { + missing = append(missing, hash) + } + } + if len(missing) > 0 { + return ErrMissingValidatedBlock{PVC: p.Channel.Name(), Channel: name, Missing: missing} + } + return nil +} + +func (p *periodic) Update(cache bcgo.Cache, network bcgo.Network, timestamp uint64) error { + entries, err := CreateValidationEntries(timestamp, p.Node, p.Channels) + if err != nil { + return err + } + name := p.Channel.Name() + head := p.Channel.Head() + var block *bcgo.Block + if head != nil { + block, err = bcgo.LoadBlock(name, cache, network, head) + if err != nil { + return err + } + } + b := CreateValidationBlock(timestamp, name, p.Node.Account().Alias(), head, block, entries) + _, _, err = bcgo.MineBlock(p.Node, p.Channel, p.Threshold, p.Listener, b) + if err != nil { + return err + } + return nil +} + +// Periodically mines a new block into the chain containing the head hashes of all open channels +func (p *periodic) Start() { + cache := p.Node.Cache() + network := p.Node.Network() + // 3 times per period + p.Ticker = time.NewTicker(p.Period / 3) + c := p.Ticker.C + for { + go func() { + for { + now := time.Now().UTC() + last := int64(p.Channel.Timestamp()) + next := time.Unix(0, last).Add(p.Period) + var timestamp uint64 + if last == 0 { + timestamp = uint64(now.UnixNano()) + } else if now.After(next) { + timestamp = uint64(next.UnixNano()) + } else { + break + } + if err := p.Update(cache, network, timestamp); err != nil { + log.Println(err) + break + } + if err := p.Channel.Push(cache, network); err != nil { + log.Println(err) + } + } + }() + if _, ok := <-c; !ok { + return + } + } +} + +func (p *periodic) Stop() { + if p.Ticker != nil { + p.Ticker.Stop() + p.Ticker = nil + } +} + +func (p *periodic) updateValidatedChannels() { + cache := p.Node.Cache() + network := p.Node.Network() + // Try update all open channels in node to the head listed in the latest validator block + block, err := bcgo.LoadBlock(p.Channel.Name(), cache, network, p.Channel.Head()) + if err != nil { + log.Println(err) + return + } + for _, entry := range block.Entry { + // Unmarshal as Reference + r := &bcgo.Reference{} + err := proto.Unmarshal(entry.Record.Payload, r) + if err != nil { + log.Println(err) + continue + } + c, err := p.Node.Channel(r.ChannelName) + if err != nil { + log.Println(err) + continue + } + b, err := bcgo.LoadBlock(r.ChannelName, cache, network, r.BlockHash) + if err == nil { + err = c.Update(cache, network, r.BlockHash, b) + } + if err != nil { + log.Println(err) + err = c.Pull(cache, network) + if err != nil { + log.Println(err) + } + } + // TODO re-mine and push channel + } +} + +func CreateValidationBlock(timestamp uint64, channel, alias string, head []byte, block *bcgo.Block, entries []*bcgo.BlockEntry) *bcgo.Block { + b := &bcgo.Block{ + Timestamp: timestamp, + ChannelName: channel, + Length: 1, + Miner: alias, + Entry: entries, + } + + if head != nil && block != nil { + b.Length = block.Length + 1 + b.Previous = head + } + + return b +} + +func CreateValidationEntries(timestamp uint64, node bcgo.Node, channels map[string]bool) ([]*bcgo.BlockEntry, error) { + var entries []*bcgo.BlockEntry + for _, channel := range node.Channels() { + name := channel.Name() + if b, ok := channels[name]; !ok || !b { + continue + } + head := channel.Head() + updated := channel.Timestamp() + if updated > timestamp { + // Channel was updated after Validation Cycle started + h := head + head = nil + // Iterate back through channel blocks until block.Timestamp <= timestamp + if err := bcgo.Iterate(name, h, nil, node.Cache(), node.Network(), func(h []byte, b *bcgo.Block) error { + if b.Timestamp <= timestamp { + head = h + updated = b.Timestamp + return bcgo.ErrStopIteration{} + } + return nil + }); err != nil { + switch err.(type) { + case bcgo.ErrStopIteration: + // Do nothing + default: + return nil, err + } + } + } + if head == nil { + continue + } + entry, err := CreateValidationEntry(timestamp, node, name, updated, head) + if err != nil { + return nil, err + } + entries = append(entries, entry) + } + return entries, nil +} + +func CreateValidationEntry(timestamp uint64, node bcgo.Node, channel string, updated uint64, head []byte) (*bcgo.BlockEntry, error) { + reference := &bcgo.Reference{ + Timestamp: updated, + ChannelName: channel, + BlockHash: head, + } + payload, err := proto.Marshal(reference) + if err != nil { + return nil, err + } + _, record, err := bcgo.CreateRecord(timestamp, node.Account(), nil, nil, payload) + if err != nil { + return nil, err + } + hash, err := cryptogo.HashProtobuf(record) + if err != nil { + return nil, err + } + return &bcgo.BlockEntry{ + RecordHash: hash, + Record: record, + }, nil +} diff --git a/vendor/aletheiaware.com/bcgo/validation/pow.go b/vendor/aletheiaware.com/bcgo/validation/pow.go new file mode 100644 index 0000000..4984b83 --- /dev/null +++ b/vendor/aletheiaware.com/bcgo/validation/pow.go @@ -0,0 +1,46 @@ +/* + * Copyright 2019-21 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package validation + +import ( + "aletheiaware.com/bcgo" +) + +type PoW interface { + bcgo.Validator +} + +type pow struct { + threshold uint64 +} + +func NewPoW(threshold uint64) PoW { + return &pow{ + threshold: threshold, + } +} + +func (v *pow) Validate(channel bcgo.Channel, cache bcgo.Cache, network bcgo.Network, hash []byte, block *bcgo.Block) error { + return bcgo.Iterate(channel.Name(), hash, block, cache, network, func(h []byte, b *bcgo.Block) error { + // Check hash ones pass threshold + ones := bcgo.Ones(h) + if ones < v.threshold { + return ErrHashTooWeak{Expected: v.threshold, Actual: ones} + } + return nil + }) +} diff --git a/vendor/aletheiaware.com/bcgo/uniquevalidation.go b/vendor/aletheiaware.com/bcgo/validation/unique.go similarity index 66% rename from vendor/aletheiaware.com/bcgo/uniquevalidation.go rename to vendor/aletheiaware.com/bcgo/validation/unique.go index c3f128d..5419d19 100644 --- a/vendor/aletheiaware.com/bcgo/uniquevalidation.go +++ b/vendor/aletheiaware.com/bcgo/validation/unique.go @@ -1,5 +1,5 @@ /* - * Copyright 2020 Aletheia Ware LLC + * Copyright 2020-21 Aletheia Ware LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,35 +14,30 @@ * limitations under the License. */ -package bcgo +package validation import ( + "aletheiaware.com/bcgo" "encoding/base64" - "fmt" ) -const ( - ERROR_DUPLICATE_BLOCK = "Duplicate Block: %s" - ERROR_DUPLICATE_ENTRY = "Duplicate Entry: %s" -) - -type UniqueValidator struct { +type Unique struct { } -func (v *UniqueValidator) Validate(channel *Channel, cache Cache, network Network, hash []byte, block *Block) error { +func (v *Unique) Validate(channel bcgo.Channel, cache bcgo.Cache, network bcgo.Network, hash []byte, block *bcgo.Block) error { blocks := make(map[string]bool) entries := make(map[string]bool) - return Iterate(channel.Name, hash, block, cache, network, func(h []byte, b *Block) error { + return bcgo.Iterate(channel.Name(), hash, block, cache, network, func(h []byte, b *bcgo.Block) error { id := base64.RawURLEncoding.EncodeToString(h) if _, ok := blocks[id]; ok { - return fmt.Errorf(ERROR_DUPLICATE_BLOCK, id) + return ErrDuplicateBlock{id} } else { blocks[id] = true } for _, entry := range b.Entry { id := base64.RawURLEncoding.EncodeToString(entry.RecordHash) if _, ok := entries[id]; ok { - return fmt.Errorf(ERROR_DUPLICATE_ENTRY, id) + return ErrDuplicateEntry{id} } else { entries[id] = true } diff --git a/vendor/aletheiaware.com/cryptogo/crypto.go b/vendor/aletheiaware.com/cryptogo/crypto.go index 4d08ca9..427d7ef 100644 --- a/vendor/aletheiaware.com/cryptogo/crypto.go +++ b/vendor/aletheiaware.com/cryptogo/crypto.go @@ -27,7 +27,6 @@ import ( "crypto/x509" "encoding/base64" "encoding/pem" - "errors" "fmt" "github.com/golang/protobuf/proto" "golang.org/x/crypto/ssh/terminal" @@ -51,16 +50,6 @@ const ( MIN_PASSWORD = 12 - ERROR_EXPORT = "Export error: %d %s" - ERROR_PASSWORD_TOO_SHORT = "Password Too Short: %d Minimum: %d" - ERROR_PASSWORDS_DO_NOT_MATCH = "Passwords Do Not Match" - ERROR_UNSUPPORTED_ENCRYPTION = "Unsupported encryption: %s" - ERROR_UNSUPPORTED_PUBLIC_KEY_TYPE = "Unsupported Public Key Type: %s" - ERROR_UNSUPPORTED_PRIVATE_KEY_TYPE = "Unsupported Private Key Type: %s" - ERROR_UNSUPPORTED_PUBLIC_KEY_FORMAT = "Unsupported Public Key Format: %s" - ERROR_UNSUPPORTED_PRIVATE_KEY_FORMAT = "Unsupported Private Key Format: %s" - ERROR_UNSUPPORTED_SIGNATURE = "Unsupported Signature Algorithm: %s" - privateKeyFileExtension = ".go.private" ) @@ -119,7 +108,7 @@ func PublicKeyToRSAPublicKey(key interface{}) (*rsa.PublicKey, error) { case *rsa.PublicKey: return k, nil default: - return nil, fmt.Errorf(ERROR_UNSUPPORTED_PUBLIC_KEY_TYPE, k) + return nil, ErrUnsupportedPublicKeyType{Type: fmt.Sprintf("%v", k)} } } @@ -170,7 +159,7 @@ func PrivateKeyToRSAPrivateKey(key interface{}) (*rsa.PrivateKey, error) { case *rsa.PrivateKey: return k, nil default: - return nil, fmt.Errorf(ERROR_UNSUPPORTED_PRIVATE_KEY_TYPE, k) + return nil, ErrUnsupportedPrivateKeyType{Type: fmt.Sprintf("%v", k)} } } @@ -183,7 +172,7 @@ func RSAPrivateKeyToPEM(privateKey *rsa.PrivateKey, password []byte) (*pem.Block return x509.EncryptPEMBlock(rand.Reader, "ENCRYPTED PRIVATE KEY", data, password, x509.PEMCipherAES128) } -func ParseRSAPublicKey(publicKey []byte, format PublicKeyFormat) (*rsa.PublicKey, error) { +func ParseRSAPublicKey(format PublicKeyFormat, publicKey []byte) (*rsa.PublicKey, error) { switch format { case PublicKeyFormat_PKCS1_PUBLIC: return RSAPublicKeyFromPKCS1Bytes(publicKey) @@ -194,11 +183,11 @@ func ParseRSAPublicKey(publicKey []byte, format PublicKeyFormat) (*rsa.PublicKey case PublicKeyFormat_UNKNOWN_PUBLIC_KEY_FORMAT: fallthrough default: - return nil, fmt.Errorf(ERROR_UNSUPPORTED_PUBLIC_KEY_FORMAT, format.String()) + return nil, ErrUnsupportedPublicKeyFormat{Format: format.String()} } } -func ParseRSAPrivateKey(privateKey []byte, format PrivateKeyFormat) (*rsa.PrivateKey, error) { +func ParseRSAPrivateKey(format PrivateKeyFormat, privateKey []byte) (*rsa.PrivateKey, error) { switch format { case PrivateKeyFormat_PKCS1_PRIVATE: return RSAPrivateKeyFromPKCS1Bytes(privateKey) @@ -207,7 +196,7 @@ func ParseRSAPrivateKey(privateKey []byte, format PrivateKeyFormat) (*rsa.Privat case PrivateKeyFormat_UNKNOWN_PRIVATE_KEY_FORMAT: fallthrough default: - return nil, fmt.Errorf(ERROR_UNSUPPORTED_PRIVATE_KEY_FORMAT, format.String()) + return nil, ErrUnsupportedPrivateKeyFormat{Format: format.String()} } } @@ -270,7 +259,7 @@ func WriteRSAPrivateKey(privateKey *rsa.PrivateKey, directory, name string, pass return nil } -func GetRSAPrivateKey(directory, name string, password []byte) (*rsa.PrivateKey, error) { +func RSAPrivateKey(directory, name string, password []byte) (*rsa.PrivateKey, error) { privateKeyPEM, err := ReadPEM(path.Join(directory, name+privateKeyFileExtension)) if err != nil { return nil, err @@ -288,12 +277,12 @@ func GetRSAPrivateKey(directory, name string, password []byte) (*rsa.PrivateKey, return PrivateKeyToRSAPrivateKey(priv) } -func GetPassword() ([]byte, error) { +func Password() ([]byte, error) { pwd, ok := os.LookupEnv("PASSWORD") if ok { return []byte(pwd), nil } else { - return ReadPassword("Enter keystore password: ") + return ReadPassword("Enter password: ") } } @@ -307,28 +296,29 @@ func ReadPassword(prompt string) ([]byte, error) { return password, nil } -func GetOrCreateRSAPrivateKey(directory, name string) (*rsa.PrivateKey, error) { - password, err := GetPassword() +func LoadRSAPrivateKey(directory, name string) (*rsa.PrivateKey, error) { + log.Println("Alias:", name) + password, err := Password() if err != nil { return nil, err } if HasRSAPrivateKey(directory, name) { - key, err := GetRSAPrivateKey(directory, name, password) + key, err := RSAPrivateKey(directory, name, password) if err != nil { return nil, err } return key, nil } else { - log.Println("Creating keystore under " + directory + " for " + name) + log.Println("Creating key in " + directory + " for " + name) - confirm, err := ReadPassword("Confirm keystore password: ") + confirm, err := ReadPassword("Confirm password: ") if err != nil { return nil, err } if !bytes.Equal(password, confirm) { - return nil, errors.New(ERROR_PASSWORDS_DO_NOT_MATCH) + return nil, ErrPasswordsDoNotMatch{} } key, err := CreateRSAPrivateKey(directory, name, password) @@ -342,7 +332,7 @@ func GetOrCreateRSAPrivateKey(directory, name string) (*rsa.PrivateKey, error) { } func ExportKeys(host, keystore, name string, password []byte) (string, error) { - privateKey, err := GetRSAPrivateKey(keystore, name, password) + privateKey, err := RSAPrivateKey(keystore, name, password) if err != nil { return "", err } @@ -385,7 +375,7 @@ func ExportKeys(host, keystore, name string, password []byte) (string, error) { log.Println("Keys exported") return base64.RawURLEncoding.EncodeToString(accessCode), nil default: - return "", fmt.Errorf(ERROR_EXPORT, response.StatusCode, response.Status) + return "", ErrExportFailed{StatusCode: response.StatusCode, Status: response.Status} } } @@ -398,6 +388,9 @@ func ImportKeys(host, keystore, name, accessCode string) error { if err != nil { return err } + if len(data) <= 0 { + return fmt.Errorf("Could not get KeyShare for %s", name) + } keyShare := &KeyShare{} if err = proto.Unmarshal(data, keyShare); err != nil { return err @@ -416,7 +409,7 @@ func ImportKeys(host, keystore, name, accessCode string) error { return err } // Parse Private Key - privateKey, err := ParseRSAPrivateKey(decryptedPrivateKey, keyShare.PrivateFormat) + privateKey, err := ParseRSAPrivateKey(keyShare.PrivateFormat, decryptedPrivateKey) if err != nil { return err } @@ -441,11 +434,11 @@ func DecryptKey(algorithm EncryptionAlgorithm, secret []byte, key *rsa.PrivateKe case EncryptionAlgorithm_UNKNOWN_ENCRYPTION: return secret, nil default: - return nil, fmt.Errorf(ERROR_UNSUPPORTED_ENCRYPTION, algorithm.String()) + return nil, ErrUnsupportedEncryption{Algorithm: algorithm.String()} } } -func DecryptPayload(algorithm EncryptionAlgorithm, key []byte, payload []byte) ([]byte, error) { +func DecryptPayload(algorithm EncryptionAlgorithm, payload []byte, key []byte) ([]byte, error) { switch algorithm { case EncryptionAlgorithm_AES_128_GCM_NOPADDING: fallthrough @@ -454,7 +447,7 @@ func DecryptPayload(algorithm EncryptionAlgorithm, key []byte, payload []byte) ( case EncryptionAlgorithm_UNKNOWN_ENCRYPTION: return payload, nil default: - return nil, fmt.Errorf(ERROR_UNSUPPORTED_ENCRYPTION, algorithm.String()) + return nil, ErrUnsupportedEncryption{Algorithm: algorithm.String()} } } @@ -513,7 +506,7 @@ func DecryptAESGCM(key, encrypted []byte) ([]byte, error) { return gcm.Open(nil, nonce, payload, nil) } -func CreateSignature(privateKey *rsa.PrivateKey, data []byte, algorithm SignatureAlgorithm) ([]byte, error) { +func CreateSignature(algorithm SignatureAlgorithm, privateKey *rsa.PrivateKey, data []byte) ([]byte, error) { switch algorithm { case SignatureAlgorithm_SHA512WITHRSA: return rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA512, data) @@ -524,11 +517,11 @@ func CreateSignature(privateKey *rsa.PrivateKey, data []byte, algorithm Signatur case SignatureAlgorithm_UNKNOWN_SIGNATURE: fallthrough default: - return nil, fmt.Errorf(ERROR_UNSUPPORTED_SIGNATURE, algorithm) + return nil, ErrUnsupportedSignature{Algorithm: algorithm.String()} } } -func VerifySignature(publicKey *rsa.PublicKey, data, signature []byte, algorithm SignatureAlgorithm) error { +func VerifySignature(algorithm SignatureAlgorithm, publicKey *rsa.PublicKey, data, signature []byte) error { switch algorithm { case SignatureAlgorithm_SHA512WITHRSA: return rsa.VerifyPKCS1v15(publicKey, crypto.SHA512, data, signature) @@ -539,7 +532,7 @@ func VerifySignature(publicKey *rsa.PublicKey, data, signature []byte, algorithm case SignatureAlgorithm_UNKNOWN_SIGNATURE: fallthrough default: - return fmt.Errorf(ERROR_UNSUPPORTED_SIGNATURE, algorithm) + return ErrUnsupportedSignature{Algorithm: algorithm.String()} } } diff --git a/vendor/aletheiaware.com/cryptogo/errors.go b/vendor/aletheiaware.com/cryptogo/errors.go new file mode 100644 index 0000000..12e3c0d --- /dev/null +++ b/vendor/aletheiaware.com/cryptogo/errors.go @@ -0,0 +1,100 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cryptogo + +import "fmt" + +// ErrExportFailed is returned when the key cannot be exported. +type ErrExportFailed struct { + StatusCode int + Status string +} + +func (e ErrExportFailed) Error() string { + return fmt.Sprintf("Export error: %d %s", e.StatusCode, e.Status) +} + +// ErrPasswordTooShort is returned when the password doesn't have enough characters. +type ErrPasswordTooShort struct { + Size, Min int +} + +func (e ErrPasswordTooShort) Error() string { + return fmt.Sprintf("Password Too Short: %d Minimum: %d", e.Size, e.Min) +} + +// ErrPasswordsDoNotMatch is returned when the password doesn't match the confirmation. +type ErrPasswordsDoNotMatch struct { +} + +func (e ErrPasswordsDoNotMatch) Error() string { + return fmt.Sprintf("Passwords Do Not Match") +} + +// ErrUnsupportedEncryption is returned when the algorithm used is not supported. +type ErrUnsupportedEncryption struct { + Algorithm string +} + +func (e ErrUnsupportedEncryption) Error() string { + return fmt.Sprintf("Unsupported encryption: %s", e.Algorithm) +} + +// ErrUnsupportedPublicKeyType is returned when the type used is not supported. +type ErrUnsupportedPublicKeyType struct { + Type string +} + +func (e ErrUnsupportedPublicKeyType) Error() string { + return fmt.Sprintf("Unsupported Public Key Type: %s", e.Type) +} + +// ErrUnsupportedPrivateKeyType is returned when the type used is not supported. +type ErrUnsupportedPrivateKeyType struct { + Type string +} + +func (e ErrUnsupportedPrivateKeyType) Error() string { + return fmt.Sprintf("Unsupported Private Key Type: %s", e.Type) +} + +// ErrUnsupportedPublicKeyFormat is returned when the format used is not supported. +type ErrUnsupportedPublicKeyFormat struct { + Format string +} + +func (e ErrUnsupportedPublicKeyFormat) Error() string { + return fmt.Sprintf("Unsupported Public Key Format: %s", e.Format) +} + +// ErrUnsupportedPrivateKeyFormat is returned when the format used is not supported. +type ErrUnsupportedPrivateKeyFormat struct { + Format string +} + +func (e ErrUnsupportedPrivateKeyFormat) Error() string { + return fmt.Sprintf("Unsupported Private Key Format: %s", e.Format) +} + +// ErrUnsupportedSignature is returned when the algorithm used is not supported. +type ErrUnsupportedSignature struct { + Algorithm string +} + +func (e ErrUnsupportedSignature) Error() string { + return fmt.Sprintf("Unsupported Signature Algorithm: %s", e.Algorithm) +} diff --git a/vendor/aletheiaware.com/cryptogo/go.mod b/vendor/aletheiaware.com/cryptogo/go.mod index 5ea1dd5..cbb9b40 100644 --- a/vendor/aletheiaware.com/cryptogo/go.mod +++ b/vendor/aletheiaware.com/cryptogo/go.mod @@ -3,6 +3,6 @@ module aletheiaware.com/cryptogo go 1.14 require ( - github.com/golang/protobuf v1.4.3 - golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad + github.com/golang/protobuf v1.5.2 + golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc ) diff --git a/vendor/aletheiaware.com/cryptogo/go.sum b/vendor/aletheiaware.com/cryptogo/go.sum index a2a9a02..bf25536 100644 --- a/vendor/aletheiaware.com/cryptogo/go.sum +++ b/vendor/aletheiaware.com/cryptogo/go.sum @@ -1,30 +1,19 @@ -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.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc h1:+q90ECDSAQirdykUN6sPEiBXBsp8Csjcca8Oy7bgLTA= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= diff --git a/vendor/aletheiaware.com/financego/finance.go b/vendor/aletheiaware.com/financego/finance.go index 5539f8c..fbe13de 100644 --- a/vendor/aletheiaware.com/financego/finance.go +++ b/vendor/aletheiaware.com/financego/finance.go @@ -18,7 +18,6 @@ package financego import ( "aletheiaware.com/bcgo" - "crypto/rsa" "github.com/golang/protobuf/proto" "log" ) @@ -39,37 +38,34 @@ type SubscriptionCallback func(*bcgo.BlockEntry, *Subscription) error type UsageRecordCallback func(*bcgo.BlockEntry, *UsageRecord) error -func GetChargeAsync(charges *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, merchantAlias string, merchantKey *rsa.PrivateKey, customerAlias string, customerKey *rsa.PrivateKey, callback ChargeCallback) error { - if err := charges.LoadCachedHead(cache); err != nil { +func ChargeAsync(charges bcgo.Channel, cache bcgo.Cache, network bcgo.Network, reader bcgo.Account, merchant, customer string, callback ChargeCallback) error { + if err := charges.Load(cache, nil); err != nil { log.Println(err) } + name := charges.Name() + head := charges.Head() cb := func(entry *bcgo.BlockEntry, key, data []byte) error { // Unmarshal as Charge charge := &Charge{} err := proto.Unmarshal(data, charge) if err != nil { return err - } else if (merchantAlias == "" || charge.MerchantAlias == merchantAlias) && (customerAlias == "" || charge.CustomerAlias == customerAlias) { + } else if (merchant == "" || charge.MerchantAlias == merchant) && (customer == "" || charge.CustomerAlias == customer) { return callback(entry, charge) } return nil } - // Read as merchant - if merchantAlias != "" && merchantKey != nil { - return bcgo.Read(charges.Name, charges.Head, nil, cache, network, merchantAlias, merchantKey, nil, cb) - } - // Read as customer - return bcgo.Read(charges.Name, charges.Head, nil, cache, network, customerAlias, customerKey, nil, cb) + return bcgo.Read(name, head, nil, cache, network, reader, nil, cb) } -func GetChargeSync(charges *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, merchantAlias string, merchantKey *rsa.PrivateKey, customerAlias string, customerKey *rsa.PrivateKey) (*Charge, error) { +func ChargeSync(charges bcgo.Channel, cache bcgo.Cache, network bcgo.Network, reader bcgo.Account, merchant, customer string) (*Charge, error) { var charge *Charge - if err := GetChargeAsync(charges, cache, network, merchantAlias, merchantKey, customerAlias, customerKey, func(e *bcgo.BlockEntry, c *Charge) error { + if err := ChargeAsync(charges, cache, network, reader, merchant, customer, func(e *bcgo.BlockEntry, c *Charge) error { charge = c - return bcgo.StopIterationError{} + return bcgo.ErrStopIteration{} }); err != nil { switch err.(type) { - case bcgo.StopIterationError: + case bcgo.ErrStopIteration: // Do nothing break default: @@ -79,37 +75,34 @@ func GetChargeSync(charges *bcgo.Channel, cache bcgo.Cache, network bcgo.Network return charge, nil } -func GetRegistrationAsync(registrations *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, merchantAlias string, merchantKey *rsa.PrivateKey, customerAlias string, customerKey *rsa.PrivateKey, callback RegistrationCallback) error { - if err := registrations.LoadCachedHead(cache); err != nil { +func RegistrationAsync(registrations bcgo.Channel, cache bcgo.Cache, network bcgo.Network, reader bcgo.Account, merchant, customer string, callback RegistrationCallback) error { + if err := registrations.Load(cache, nil); err != nil { log.Println(err) } + name := registrations.Name() + head := registrations.Head() cb := func(entry *bcgo.BlockEntry, key, data []byte) error { // Unmarshal as Registration registration := &Registration{} err := proto.Unmarshal(data, registration) if err != nil { return err - } else if (merchantAlias == "" || registration.MerchantAlias == merchantAlias) && (customerAlias == "" || registration.CustomerAlias == customerAlias) { + } else if (merchant == "" || registration.MerchantAlias == merchant) && (customer == "" || registration.CustomerAlias == customer) { return callback(entry, registration) } return nil } - // Read as merchant - if merchantAlias != "" && merchantKey != nil { - return bcgo.Read(registrations.Name, registrations.Head, nil, cache, network, merchantAlias, merchantKey, nil, cb) - } - // Read as customer - return bcgo.Read(registrations.Name, registrations.Head, nil, cache, network, customerAlias, customerKey, nil, cb) + return bcgo.Read(name, head, nil, cache, network, reader, nil, cb) } -func GetRegistrationSync(registrations *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, merchantAlias string, merchantKey *rsa.PrivateKey, customerAlias string, customerKey *rsa.PrivateKey) (*Registration, error) { +func RegistrationSync(registrations bcgo.Channel, cache bcgo.Cache, network bcgo.Network, reader bcgo.Account, merchant, customer string) (*Registration, error) { var registration *Registration - if err := GetRegistrationAsync(registrations, cache, network, merchantAlias, merchantKey, customerAlias, customerKey, func(e *bcgo.BlockEntry, r *Registration) error { + if err := RegistrationAsync(registrations, cache, network, reader, merchant, customer, func(e *bcgo.BlockEntry, r *Registration) error { registration = r - return bcgo.StopIterationError{} + return bcgo.ErrStopIteration{} }); err != nil { switch err.(type) { - case bcgo.StopIterationError: + case bcgo.ErrStopIteration: // Do nothing break default: @@ -119,37 +112,34 @@ func GetRegistrationSync(registrations *bcgo.Channel, cache bcgo.Cache, network return registration, nil } -func GetSubscriptionAsync(subscriptions *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, merchantAlias string, merchantKey *rsa.PrivateKey, customerAlias string, customerKey *rsa.PrivateKey, productId, planId string, callback SubscriptionCallback) error { - if err := subscriptions.LoadCachedHead(cache); err != nil { +func SubscriptionAsync(subscriptions bcgo.Channel, cache bcgo.Cache, network bcgo.Network, reader bcgo.Account, merchant, customer string, productId, planId string, callback SubscriptionCallback) error { + if err := subscriptions.Load(cache, nil); err != nil { log.Println(err) } + name := subscriptions.Name() + head := subscriptions.Head() cb := func(entry *bcgo.BlockEntry, key, data []byte) error { // Unmarshal as Subscription subscription := &Subscription{} err := proto.Unmarshal(data, subscription) if err != nil { return err - } else if (merchantAlias == "" || subscription.MerchantAlias == merchantAlias) && (customerAlias == "" || subscription.CustomerAlias == customerAlias) && (productId == "" || subscription.ProductId == productId) && (planId == "" || subscription.PlanId == planId) { + } else if (merchant == "" || subscription.MerchantAlias == merchant) && (customer == "" || subscription.CustomerAlias == customer) && (productId == "" || subscription.ProductId == productId) && (planId == "" || subscription.PlanId == planId) { return callback(entry, subscription) } return nil } - // Read as merchant - if merchantAlias != "" && merchantKey != nil { - return bcgo.Read(subscriptions.Name, subscriptions.Head, nil, cache, network, merchantAlias, merchantKey, nil, cb) - } - // Read as customer - return bcgo.Read(subscriptions.Name, subscriptions.Head, nil, cache, network, customerAlias, customerKey, nil, cb) + return bcgo.Read(name, head, nil, cache, network, reader, nil, cb) } -func GetSubscriptionSync(subscriptions *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, merchantAlias string, merchantKey *rsa.PrivateKey, customerAlias string, customerKey *rsa.PrivateKey, productId, planId string) (*Subscription, error) { +func SubscriptionSync(subscriptions bcgo.Channel, cache bcgo.Cache, network bcgo.Network, reader bcgo.Account, merchant, customer string, productId, planId string) (*Subscription, error) { var subscription *Subscription - if err := GetSubscriptionAsync(subscriptions, cache, network, merchantAlias, merchantKey, customerAlias, customerKey, productId, planId, func(e *bcgo.BlockEntry, s *Subscription) error { + if err := SubscriptionAsync(subscriptions, cache, network, reader, merchant, customer, productId, planId, func(e *bcgo.BlockEntry, s *Subscription) error { subscription = s - return bcgo.StopIterationError{} + return bcgo.ErrStopIteration{} }); err != nil { switch err.(type) { - case bcgo.StopIterationError: + case bcgo.ErrStopIteration: // Do nothing break default: @@ -159,37 +149,34 @@ func GetSubscriptionSync(subscriptions *bcgo.Channel, cache bcgo.Cache, network return subscription, nil } -func GetUsageRecordAsync(usages *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, merchantAlias string, merchantKey *rsa.PrivateKey, customerAlias string, customerKey *rsa.PrivateKey, callback UsageRecordCallback) error { - if err := usages.LoadCachedHead(cache); err != nil { +func UsageRecordAsync(usages bcgo.Channel, cache bcgo.Cache, network bcgo.Network, reader bcgo.Account, merchant, customer string, callback UsageRecordCallback) error { + if err := usages.Load(cache, nil); err != nil { log.Println(err) } + name := usages.Name() + head := usages.Head() cb := func(entry *bcgo.BlockEntry, key, data []byte) error { // Unmarshal as UsageRecord usage := &UsageRecord{} err := proto.Unmarshal(data, usage) if err != nil { return err - } else if (merchantAlias == "" || usage.MerchantAlias == merchantAlias) && (customerAlias == "" || usage.CustomerAlias == customerAlias) { + } else if (merchant == "" || usage.MerchantAlias == merchant) && (customer == "" || usage.CustomerAlias == customer) { return callback(entry, usage) } return nil } - // Read as merchant - if merchantAlias != "" && merchantKey != nil { - return bcgo.Read(usages.Name, usages.Head, nil, cache, network, merchantAlias, merchantKey, nil, cb) - } - // Read as customer - return bcgo.Read(usages.Name, usages.Head, nil, cache, network, customerAlias, customerKey, nil, cb) + return bcgo.Read(name, head, nil, cache, network, reader, nil, cb) } -func GetUsageRecordSync(usages *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, merchantAlias string, merchantKey *rsa.PrivateKey, customerAlias string, customerKey *rsa.PrivateKey) (*UsageRecord, error) { +func UsageRecordSync(usages bcgo.Channel, cache bcgo.Cache, network bcgo.Network, reader bcgo.Account, merchant, customer string) (*UsageRecord, error) { var usage *UsageRecord - if err := GetUsageRecordAsync(usages, cache, network, merchantAlias, merchantKey, customerAlias, customerKey, func(e *bcgo.BlockEntry, u *UsageRecord) error { + if err := UsageRecordAsync(usages, cache, network, reader, merchant, customer, func(e *bcgo.BlockEntry, u *UsageRecord) error { usage = u - return bcgo.StopIterationError{} + return bcgo.ErrStopIteration{} }); err != nil { switch err.(type) { - case bcgo.StopIterationError: + case bcgo.ErrStopIteration: // Do nothing break default: diff --git a/vendor/aletheiaware.com/financego/finance_server.go b/vendor/aletheiaware.com/financego/finance_server.go index a5f8876..b574e34 100644 --- a/vendor/aletheiaware.com/financego/finance_server.go +++ b/vendor/aletheiaware.com/financego/finance_server.go @@ -19,34 +19,28 @@ package financego import ( "aletheiaware.com/aliasgo" "aletheiaware.com/bcgo" - "crypto/rsa" "github.com/golang/protobuf/proto" "log" ) -func Register(merchant *bcgo.Node, processor Processor, aliases, registrations *bcgo.Channel, threshold uint64, listener bcgo.MiningListener) func(string, string, string) (string, *bcgo.Reference, error) { +func Register(merchant bcgo.Node, processor Processor, aliases, registrations bcgo.Channel, threshold uint64, listener bcgo.MiningListener) func(string, string, string) (string, *bcgo.Reference, error) { return func(customerAlias, customerEmail, customerToken string) (string, *bcgo.Reference, error) { - cache := merchant.Cache - network := merchant.Network + merchantAlias := merchant.Account().Alias() + cache := merchant.Cache() + network := merchant.Network() if err := aliases.Refresh(cache, network); err != nil { log.Println(err) } - // Get rsa.PublicKey for Alias - publicKey, err := aliasgo.GetPublicKey(aliases, cache, network, customerAlias) - if err != nil { - return "", nil, err - } - // Create list of access (user + server) - acl := map[string]*rsa.PublicKey{ - customerAlias: publicKey, - merchant.Alias: &merchant.Key.PublicKey, - } - log.Println("Access", acl) + access := aliasgo.PublicKeysForAliases(aliases, cache, network, []string{ + customerAlias, + merchantAlias, + }) + log.Println("Access", access) - registration, err := processor.NewRegistration(merchant.Alias, customerAlias, customerEmail, customerToken, customerAlias+" "+merchant.Alias) + registration, err := processor.NewRegistration(merchantAlias, customerAlias, customerEmail, customerToken, customerAlias+" "+merchantAlias) if err != nil { return "", nil, err } @@ -60,12 +54,12 @@ func Register(merchant *bcgo.Node, processor Processor, aliases, registrations * log.Println(err) } - _, err = merchant.Write(bcgo.Timestamp(), registrations, acl, nil, registrationData) + _, err = merchant.Write(bcgo.Timestamp(), registrations, access, nil, registrationData) if err != nil { return "", nil, err } - registrationHash, registrationBlock, err := merchant.Mine(registrations, threshold, listener) + registrationHash, registrationBlock, err := bcgo.Mine(merchant, registrations, threshold, listener) if err != nil { return "", nil, err } @@ -88,29 +82,24 @@ func Register(merchant *bcgo.Node, processor Processor, aliases, registrations * } } -func Subscribe(merchant *bcgo.Node, processor Processor, aliases, subscriptions *bcgo.Channel, threshold uint64, listener bcgo.MiningListener, productId, planId string) func(string, string) (string, *bcgo.Reference, error) { +func Subscribe(merchant bcgo.Node, processor Processor, aliases, subscriptions bcgo.Channel, threshold uint64, listener bcgo.MiningListener, productId, planId string) func(string, string) (string, *bcgo.Reference, error) { return func(customerAlias, customerID string) (string, *bcgo.Reference, error) { - cache := merchant.Cache - network := merchant.Network + merchantAlias := merchant.Account().Alias() + cache := merchant.Cache() + network := merchant.Network() if err := aliases.Refresh(cache, network); err != nil { log.Println(err) } - // Get rsa.PublicKey for Alias - publicKey, err := aliasgo.GetPublicKey(aliases, cache, network, customerAlias) - if err != nil { - return "", nil, err - } - // Create list of access (user + server) - acl := map[string]*rsa.PublicKey{ - customerAlias: publicKey, - merchant.Alias: &merchant.Key.PublicKey, - } + acl := aliasgo.PublicKeysForAliases(aliases, cache, network, []string{ + customerAlias, + merchantAlias, + }) log.Println("Access", acl) - subscription, err := processor.NewSubscription(merchant.Alias, customerAlias, customerID, "", productId, planId) + subscription, err := processor.NewSubscription(merchantAlias, customerAlias, customerID, "", productId, planId) if err != nil { return "", nil, err } @@ -129,7 +118,7 @@ func Subscribe(merchant *bcgo.Node, processor Processor, aliases, subscriptions return "", nil, err } - subscriptionHash, subscriptionBlock, err := merchant.Mine(subscriptions, threshold, listener) + subscriptionHash, subscriptionBlock, err := bcgo.Mine(merchant, subscriptions, threshold, listener) if err != nil { return "", nil, err } diff --git a/vendor/aletheiaware.com/financego/go.mod b/vendor/aletheiaware.com/financego/go.mod index 45f9b23..5e27064 100644 --- a/vendor/aletheiaware.com/financego/go.mod +++ b/vendor/aletheiaware.com/financego/go.mod @@ -3,10 +3,9 @@ module aletheiaware.com/financego go 1.14 require ( - aletheiaware.com/aliasgo v1.1.3 - aletheiaware.com/bcgo v1.1.4 - aletheiaware.com/testinggo v1.1.2 - github.com/golang/protobuf v1.4.3 - github.com/stretchr/testify v1.7.0 // indirect + aletheiaware.com/aliasgo v1.2.3 + aletheiaware.com/bcgo v1.2.3 + aletheiaware.com/testinggo v1.2.2 + github.com/golang/protobuf v1.5.2 github.com/stripe/stripe-go v70.15.0+incompatible ) diff --git a/vendor/aletheiaware.com/financego/go.sum b/vendor/aletheiaware.com/financego/go.sum index d79e0d1..fc99400 100644 --- a/vendor/aletheiaware.com/financego/go.sum +++ b/vendor/aletheiaware.com/financego/go.sum @@ -1,24 +1,18 @@ -aletheiaware.com/aliasgo v1.1.3 h1:RnJhpWcbH7KWWWgIvUCVS+++mzpjYNk/dQm4o1G0lX8= -aletheiaware.com/aliasgo v1.1.3/go.mod h1:JY9/j4q6ZniHb0vKO7CJJ3M03eTVhczoIIhJBZ6Sa3w= -aletheiaware.com/bcgo v1.1.4 h1:HuAk12UeOvtIXlc7WN2XIj9tV+jNA5uCi+D8Z0V2twU= -aletheiaware.com/bcgo v1.1.4/go.mod h1:GXvFFZ8JrATGrvuKA0J3ucf9+91eC94ggphNVpg3XUM= -aletheiaware.com/cryptogo v1.1.1 h1:XrzGXcTgYQbuL3tQv/idVzAIblb2k+o77iigiQiXTUQ= -aletheiaware.com/cryptogo v1.1.1/go.mod h1:sT8jDe5zWSIswZDAilLwfX2N6l4WOFQBm+4lYxx1Ae0= -aletheiaware.com/testinggo v1.1.2 h1:/zCBvslySEY4uJ2qnnyvhFdgIERa/jzlgHBOmS4lL1k= -aletheiaware.com/testinggo v1.1.2/go.mod h1:bqmrqRyMkGbTa9E/1D8xHE0KLmOw+HRG0skc/XwrdcY= +aletheiaware.com/aliasgo v1.2.3 h1:joMErbHdyo+jVbIoA9HWMPmUVfhZjabBVaB5AnYYObQ= +aletheiaware.com/aliasgo v1.2.3/go.mod h1:wSp0m2ZOXA3M3ZKFcUtcf2ANBio5JSXxQx07IpxwaGM= +aletheiaware.com/bcgo v1.2.3 h1:5vRjjrkmlSh0/cwhY5u+0S4RUpvTCAMN1HVJMBl9A88= +aletheiaware.com/bcgo v1.2.3/go.mod h1:zNPBDrox6aUVv8ns5UOzcaDXzD/p5tZ0lGSxlfT6/Rs= +aletheiaware.com/cryptogo v1.2.2 h1:d7vEEgf3bZFnLk+HG1wCAY/pgRz+zNYvKFpxsli3Mng= +aletheiaware.com/cryptogo v1.2.2/go.mod h1:B1mJVIsfEDJoovkD2fLsZXgXxR1AAe2cDmjFwt7Eau4= +aletheiaware.com/testinggo v1.2.2 h1:w+ir8ehcnIcZ+jTjalGWAkh3So9PaJm5g3CPgLnPtXE= +aletheiaware.com/testinggo v1.2.2/go.mod h1:TijVTRIGnue9UHlxT9YgLp5VGWOo4PI9VRflCm4v4xo= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -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.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= @@ -27,27 +21,22 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stripe/stripe-go v70.15.0+incompatible h1:hNML7M1zx8RgtepEMlxyu/FpVPrP7KZm1gPFQquJQvM= github.com/stripe/stripe-go v70.15.0+incompatible/go.mod h1:A1dQZmO/QypXmsL0T8axYZkSN/uA/T/A64pfKdBAMiY= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc h1:+q90ECDSAQirdykUN6sPEiBXBsp8Csjcca8Oy7bgLTA= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= diff --git a/vendor/aletheiaware.com/spaceclientgo/README.md b/vendor/aletheiaware.com/spaceclientgo/README.md index 6064470..6d17b04 100644 --- a/vendor/aletheiaware.com/spaceclientgo/README.md +++ b/vendor/aletheiaware.com/spaceclientgo/README.md @@ -15,9 +15,7 @@ This is a Go implementation of a S P A C E client - secure, private, storage. Install the binary (or download from https://github.com/AletheiaWareLLC/spaceclientgo/releases/latest) -``` -go install -tags release aletheiaware.com/spaceclientgo/cmd/space -``` + go install -tags release aletheiaware.com/spaceclientgo/cmd/space # Usage diff --git a/vendor/aletheiaware.com/spaceclientgo/client.go b/vendor/aletheiaware.com/spaceclientgo/client.go index 62dd582..0e0bbcc 100644 --- a/vendor/aletheiaware.com/spaceclientgo/client.go +++ b/vendor/aletheiaware.com/spaceclientgo/client.go @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 Aletheia Ware LLC + * Copyright 2019-2021 Aletheia Ware LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,54 +22,65 @@ import ( "aletheiaware.com/financego" "aletheiaware.com/spacego" "bytes" - "crypto/rsa" + "context" "encoding/base64" "github.com/golang/protobuf/proto" "io" "log" + "reflect" + "time" ) -type SpaceClient struct { +type SpaceClient interface { bcclientgo.BCClient + + Add(bcgo.Node, bcgo.MiningListener, string, string, io.Reader) (*bcgo.Reference, error) + Amend(bcgo.Node, bcgo.MiningListener, bcgo.Channel, ...*spacego.Delta) error + MetaForHash(bcgo.Node, []byte, spacego.MetaCallback) error + AllMetas(bcgo.Node, spacego.MetaCallback) error + ReadFile(bcgo.Node, []byte) (io.Reader, error) + WriteFile(bcgo.Node, bcgo.MiningListener, []byte) (io.WriteCloser, error) + WatchFile(context.Context, bcgo.Node, []byte, func()) + + /* + AddPreview(bcgo.Node, bcgo.MiningListener, []byte, []string) ([]*bcgo.Reference, error) + AllPreviewsForHash(bcgo.Node, []byte, spacego.PreviewCallback) error + */ + + AddTag(bcgo.Node, bcgo.MiningListener, []byte, []string) ([]*bcgo.Reference, error) + AllTagsForHash(bcgo.Node, []byte, spacego.TagCallback) error + + SearchMeta(bcgo.Node, spacego.MetaFilter, spacego.MetaCallback) error + SearchTag(bcgo.Node, spacego.TagFilter, spacego.MetaCallback) error + + Registration(string, financego.RegistrationCallback) error + Subscription(string, financego.SubscriptionCallback) error } -func NewSpaceClient(peers ...string) *SpaceClient { +type spaceClient struct { + bcclientgo.BCClient +} + +func NewSpaceClient(peers ...string) SpaceClient { if len(peers) == 0 { peers = append( - spacego.GetSpaceHosts(), // Add SPACE host as peer - bcgo.GetBCHost(), // Add BC host as peer + spacego.SpaceHosts(), // Add SPACE host as peer + bcgo.BCHost(), // Add BC host as peer ) } - return &SpaceClient{ - BCClient: *bcclientgo.NewBCClient(peers...), + return &spaceClient{ + BCClient: bcclientgo.NewBCClient(peers...), } } -func (c *SpaceClient) Init(listener bcgo.MiningListener) (*bcgo.Node, error) { - root, err := c.GetRoot() - if err != nil { - return nil, err - } - - // Add Space hosts to peers - for _, host := range spacego.GetSpaceHosts() { - if err := bcgo.AddPeer(root, host); err != nil { - return nil, err - } - } - - // Add BC host to peers - if err := bcgo.AddPeer(root, bcgo.GetBCHost()); err != nil { - return nil, err - } - - return c.BCClient.Init(listener) -} - // Adds file -func (c *SpaceClient) Add(node *bcgo.Node, listener bcgo.MiningListener, name, mime string, reader io.Reader) (*bcgo.Reference, error) { - metas := spacego.OpenMetaChannel(node.Alias) - if err := metas.Refresh(node.Cache, node.Network); err != nil { +func (c *spaceClient) Add(node bcgo.Node, listener bcgo.MiningListener, name, mime string, reader io.Reader) (*bcgo.Reference, error) { + account := node.Account() + alias := account.Alias() + metas := node.OpenChannel(spacego.MetaChannelName(alias), func() bcgo.Channel { + return spacego.OpenMetaChannel(alias) + }) + if err := metas.Refresh(node.Cache(), node.Network()); err != nil { log.Println(err) } @@ -84,31 +95,34 @@ func (c *SpaceClient) Add(node *bcgo.Node, listener bcgo.MiningListener, name, m return nil, err } - acl := map[string]*rsa.PublicKey{ - node.Alias: &node.Key.PublicKey, - } - // Write meta data - reference, err := node.Write(bcgo.Timestamp(), metas, acl, nil, data) + reference, err := node.Write(bcgo.Timestamp(), metas, []bcgo.Identity{account}, nil, data) if err != nil { return nil, err } // Mine meta channel - if _, _, err := node.Mine(metas, spacego.THRESHOLD, listener); err != nil { + if _, _, err := bcgo.Mine(node, metas, spacego.THRESHOLD_CUSTOMER, listener); err != nil { return nil, err } - if n := node.Network; n != nil { + if n := node.Network(); n != nil && !reflect.ValueOf(n).IsNil() { // Push update to peers - if err := metas.Push(node.Cache, n); err != nil { + if err := metas.Push(node.Cache(), n); err != nil { log.Println(err) } } + if reader == nil { + return reference, nil + } + metaId := base64.RawURLEncoding.EncodeToString(reference.RecordHash) - deltas := spacego.OpenDeltaChannel(metaId) - if err := deltas.Refresh(node.Cache, node.Network); err != nil { + + deltas := node.OpenChannel(spacego.DeltaChannelName(metaId), func() bcgo.Channel { + return spacego.OpenDeltaChannel(metaId) + }) + if err := deltas.Refresh(node.Cache(), node.Network()); err != nil { log.Println(err) } @@ -127,11 +141,11 @@ func (c *SpaceClient) Add(node *bcgo.Node, listener bcgo.MiningListener, name, m timestamp = bcgo.Timestamp() } last = timestamp - _, record, err := bcgo.CreateRecord(timestamp, node.Alias, node.Key, acl, nil, data) + _, record, err := bcgo.CreateRecord(timestamp, account, []bcgo.Identity{account}, nil, data) if err != nil { return err } - if _, err := bcgo.WriteRecord(deltas.Name, node.Cache, record); err != nil { + if _, err := bcgo.WriteRecord(deltas.Name(), node.Cache(), record); err != nil { return err } return nil @@ -140,13 +154,13 @@ func (c *SpaceClient) Add(node *bcgo.Node, listener bcgo.MiningListener, name, m } // Mine file channel - if _, _, err := node.Mine(deltas, spacego.THRESHOLD, listener); err != nil { + if _, _, err := bcgo.Mine(node, deltas, spacego.THRESHOLD_CUSTOMER, listener); err != nil { return nil, err } - if n := node.Network; n != nil { + if n := node.Network(); n != nil && !reflect.ValueOf(n).IsNil() { // Push update to peers - if err := deltas.Push(node.Cache, n); err != nil { + if err := deltas.Push(node.Cache(), n); err != nil { log.Println(err) } } @@ -155,60 +169,81 @@ func (c *SpaceClient) Add(node *bcgo.Node, listener bcgo.MiningListener, name, m return reference, nil } -// Append adds the given delta to the file -func (c *SpaceClient) Append(node *bcgo.Node, listener bcgo.MiningListener, deltas *bcgo.Channel, acl map[string]*rsa.PublicKey, delta *spacego.Delta) error { - data, err := proto.Marshal(delta) - if err != nil { - return err - } - _, record, err := bcgo.CreateRecord(bcgo.Timestamp(), node.Alias, node.Key, acl, nil, data) - if err != nil { - return err +// Amend adds the given delta to the file +func (c *spaceClient) Amend(node bcgo.Node, listener bcgo.MiningListener, channel bcgo.Channel, deltas ...*spacego.Delta) error { + if len(deltas) == 0 { + return nil } - if _, err := bcgo.WriteRecord(deltas.Name, node.Cache, record); err != nil { - return err + account := node.Account() + access := []bcgo.Identity{account} + name := channel.Name() + cache := node.Cache() + for _, d := range deltas { + data, err := proto.Marshal(d) + if err != nil { + return err + } + + _, record, err := bcgo.CreateRecord(bcgo.Timestamp(), account, access, nil, data) + if err != nil { + return err + } + + if _, err := bcgo.WriteRecord(name, cache, record); err != nil { + return err + } } + // Mine file channel - if _, _, err := node.Mine(deltas, spacego.THRESHOLD, listener); err != nil { + if _, _, err := bcgo.Mine(node, channel, spacego.THRESHOLD_CUSTOMER, listener); err != nil { return err } - if n := node.Network; n != nil { + if n := node.Network(); n != nil && !reflect.ValueOf(n).IsNil() { // Push update to peers - if err := deltas.Push(node.Cache, n); err != nil { + if err := channel.Push(node.Cache(), n); err != nil { log.Println(err) } } return nil } -// List files owned by key -func (c *SpaceClient) List(node *bcgo.Node, callback spacego.MetaCallback) error { - metas := spacego.OpenMetaChannel(node.Alias) - if err := metas.Refresh(node.Cache, node.Network); err != nil { +// MetaForHash owned by key with given meta ID +func (c *spaceClient) MetaForHash(node bcgo.Node, recordHash []byte, callback spacego.MetaCallback) error { + alias := node.Account().Alias() + metas := node.OpenChannel(spacego.MetaChannelName(alias), func() bcgo.Channel { + return spacego.OpenMetaChannel(alias) + }) + if err := metas.Refresh(node.Cache(), node.Network()); err != nil { log.Println(err) } - return spacego.GetMeta(metas, node.Cache, node.Network, node.Alias, node.Key, nil, func(entry *bcgo.BlockEntry, meta *spacego.Meta) error { + return spacego.ReadMeta(metas, node.Cache(), node.Network(), node.Account(), recordHash, func(entry *bcgo.BlockEntry, meta *spacego.Meta) error { return callback(entry, meta) }) } -// GetMeta owned by key with given hash -func (c *SpaceClient) GetMeta(node *bcgo.Node, recordHash []byte, callback spacego.MetaCallback) error { - metas := spacego.OpenMetaChannel(node.Alias) - if err := metas.Refresh(node.Cache, node.Network); err != nil { +// AllMetas lists files owned by key +func (c *spaceClient) AllMetas(node bcgo.Node, callback spacego.MetaCallback) error { + alias := node.Account().Alias() + metas := node.OpenChannel(spacego.MetaChannelName(alias), func() bcgo.Channel { + return spacego.OpenMetaChannel(alias) + }) + if err := metas.Refresh(node.Cache(), node.Network()); err != nil { log.Println(err) } - return spacego.GetMeta(metas, node.Cache, node.Network, node.Alias, node.Key, recordHash, func(entry *bcgo.BlockEntry, meta *spacego.Meta) error { + return spacego.ReadMeta(metas, node.Cache(), node.Network(), node.Account(), nil, func(entry *bcgo.BlockEntry, meta *spacego.Meta) error { return callback(entry, meta) }) } -// ReadFile with the given hash -func (c *SpaceClient) ReadFile(node *bcgo.Node, metaId []byte) (io.Reader, error) { +// ReadFile with the given meta ID. +func (c *spaceClient) ReadFile(node bcgo.Node, metaId []byte) (io.Reader, error) { // TODO read from cache if file exists - deltas := spacego.OpenDeltaChannel(base64.RawURLEncoding.EncodeToString(metaId)) - if err := deltas.Refresh(node.Cache, node.Network); err != nil { + mId := base64.RawURLEncoding.EncodeToString(metaId) + deltas := node.OpenChannel(spacego.DeltaChannelName(mId), func() bcgo.Channel { + return spacego.OpenDeltaChannel(mId) + }) + if err := deltas.Refresh(node.Cache(), node.Network()); err != nil { log.Println(err) } buffer := []byte{} @@ -221,43 +256,143 @@ func (c *SpaceClient) ReadFile(node *bcgo.Node, metaId []byte) (io.Reader, error return bytes.NewReader(buffer), nil } -// Search files owned by key -func (c *SpaceClient) Search(node *bcgo.Node, terms []string, callback spacego.MetaCallback) error { - metas := spacego.OpenMetaChannel(node.Alias) - if err := metas.Refresh(node.Cache, node.Network); err != nil { +// WriteFile with the given meta ID. +func (c *spaceClient) WriteFile(node bcgo.Node, listener bcgo.MiningListener, metaId []byte) (io.WriteCloser, error) { + mId := base64.RawURLEncoding.EncodeToString(metaId) + deltas := node.OpenChannel(spacego.DeltaChannelName(mId), func() bcgo.Channel { + return spacego.OpenDeltaChannel(mId) + }) + if err := deltas.Refresh(node.Cache(), node.Network()); err != nil { log.Println(err) } - if err := spacego.GetMeta(metas, node.Cache, node.Network, node.Alias, node.Key, nil, func(metaEntry *bcgo.BlockEntry, meta *spacego.Meta) error { - tags := spacego.OpenTagChannel(base64.RawURLEncoding.EncodeToString(metaEntry.RecordHash)) - if err := tags.Refresh(node.Cache, node.Network); err != nil { - log.Println(err) + // Read current file into a old buffer + old := []byte{} + if err := spacego.IterateDeltas(node, deltas, func(entry *bcgo.BlockEntry, delta *spacego.Delta) error { + old = spacego.ApplyDelta(delta, old) + return nil + }); err != nil { + return nil, err + } + var new bytes.Buffer + return spacego.NewCloser(&new, func() error { + return c.Amend(node, listener, deltas, spacego.Difference(old, new.Bytes())...) + }), nil +} + +// WatchFile triggers the given callback whenever the file with given meta ID updates. +func (c *spaceClient) WatchFile(ctx context.Context, node bcgo.Node, metaId []byte, callback func()) { + initial := time.Second + limit := time.Hour + duration := initial + ticker := time.NewTicker(duration) + mId := base64.RawURLEncoding.EncodeToString(metaId) + deltas := node.OpenChannel(spacego.DeltaChannelName(mId), func() bcgo.Channel { + return spacego.OpenDeltaChannel(mId) + }) + deltas.AddTrigger(func() { + if ctx.Err() != nil { + // Context was already cancelled + return } - return spacego.GetTag(tags, node.Cache, node.Network, node.Alias, node.Key, nil, func(tagEntry *bcgo.BlockEntry, tag *spacego.Tag) error { - for _, value := range terms { - if tag.Value == value { - return callback(metaEntry, meta) + go callback() + }) + // TODO replace polling with mechanism to register with provider to listen for remote updates + go func() { + defer ticker.Stop() + var errors int + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + head := deltas.Head() + if err := deltas.Refresh(node.Cache(), node.Network()); err != nil { + log.Println(err) + } + if bytes.Equal(head, deltas.Head()) { + // No change + errors++ + if errors > 3 { + // Too many errors, exponential backoff + duration *= 2 + if duration > limit { + duration = limit + } + errors = 0 + } + } else { + // Change, reset duration + duration = initial + errors = 0 } + ticker.Stop() + ticker = time.NewTicker(duration) } + } + }() +} + +// SearchMeta searches files by metadata +func (c *spaceClient) SearchMeta(node bcgo.Node, filter spacego.MetaFilter, callback spacego.MetaCallback) error { + account := node.Account() + alias := account.Alias() + metas := node.OpenChannel(spacego.MetaChannelName(alias), func() bcgo.Channel { + return spacego.OpenMetaChannel(alias) + }) + if err := metas.Refresh(node.Cache(), node.Network()); err != nil { + log.Println(err) + } + if err := spacego.ReadMeta(metas, node.Cache(), node.Network(), account, nil, func(metaEntry *bcgo.BlockEntry, meta *spacego.Meta) error { + if filter != nil && !filter.Filter(meta) { + // Meta doesn't pass filter return nil - }) + } + return callback(metaEntry, meta) }); err != nil { return err } return nil } -// AddTag adds the given tag for the file with the given hash -func (c *SpaceClient) AddTag(node *bcgo.Node, listener bcgo.MiningListener, metaId []byte, tag []string) ([]*bcgo.Reference, error) { - metas := spacego.OpenMetaChannel(node.Alias) - if err := metas.Refresh(node.Cache, node.Network); err != nil { +// SearchTag searches files by tag +func (c *spaceClient) SearchTag(node bcgo.Node, filter spacego.TagFilter, callback spacego.MetaCallback) error { + return c.SearchMeta(node, nil, func(metaEntry *bcgo.BlockEntry, meta *spacego.Meta) error { + metaId := base64.RawURLEncoding.EncodeToString(metaEntry.RecordHash) + tags := node.OpenChannel(spacego.TagChannelName(metaId), func() bcgo.Channel { + return spacego.OpenTagChannel(metaId) + }) + if err := tags.Refresh(node.Cache(), node.Network()); err != nil { + log.Println(err) + } + return spacego.ReadTag(tags, node.Cache(), node.Network(), node.Account(), nil, func(tagEntry *bcgo.BlockEntry, tag *spacego.Tag) error { + if filter != nil && !filter.Filter(tag) { + // Tag doesn't pass filter + return nil + } + return callback(metaEntry, meta) + }) + }) +} + +// AddTag adds the given tag for the file with the given meta ID +func (c *spaceClient) AddTag(node bcgo.Node, listener bcgo.MiningListener, metaId []byte, tag []string) ([]*bcgo.Reference, error) { + account := node.Account() + alias := account.Alias() + metas := node.OpenChannel(spacego.MetaChannelName(alias), func() bcgo.Channel { + return spacego.OpenMetaChannel(alias) + }) + if err := metas.Refresh(node.Cache(), node.Network()); err != nil { log.Println(err) } - tags := spacego.OpenTagChannel(base64.RawURLEncoding.EncodeToString(metaId)) - if err := tags.Refresh(node.Cache, node.Network); err != nil { + mId := base64.RawURLEncoding.EncodeToString(metaId) + tags := node.OpenChannel(spacego.TagChannelName(mId), func() bcgo.Channel { + return spacego.OpenTagChannel(mId) + }) + if err := tags.Refresh(node.Cache(), node.Network()); err != nil { log.Println(err) } var references []*bcgo.Reference - if err := spacego.GetMeta(metas, node.Cache, node.Network, node.Alias, node.Key, metaId, func(entry *bcgo.BlockEntry, meta *spacego.Meta) error { + if err := spacego.ReadMeta(metas, node.Cache(), node.Network(), account, metaId, func(entry *bcgo.BlockEntry, meta *spacego.Meta) error { for _, t := range tag { tag := spacego.Tag{ Value: t, @@ -266,20 +401,17 @@ func (c *SpaceClient) AddTag(node *bcgo.Node, listener bcgo.MiningListener, meta if err != nil { return err } - acl := map[string]*rsa.PublicKey{ - node.Alias: &node.Key.PublicKey, - } references := []*bcgo.Reference{&bcgo.Reference{ Timestamp: entry.Record.Timestamp, - ChannelName: metas.Name, + ChannelName: metas.Name(), RecordHash: metaId, }} - reference, err := node.Write(bcgo.Timestamp(), tags, acl, references, data) + reference, err := node.Write(bcgo.Timestamp(), tags, []bcgo.Identity{account}, references, data) if err != nil { return err } references = append(references, reference) - if _, _, err := node.Mine(tags, spacego.THRESHOLD, listener); err != nil { + if _, _, err := bcgo.Mine(node, tags, spacego.THRESHOLD_CUSTOMER, listener); err != nil { return err } } @@ -290,13 +422,16 @@ func (c *SpaceClient) AddTag(node *bcgo.Node, listener bcgo.MiningListener, meta return references, nil } -// GetTag returns all tags for the file with the given hash -func (c *SpaceClient) GetTag(node *bcgo.Node, metaId []byte, callback func(entry *bcgo.BlockEntry, tag *spacego.Tag)) error { - tags := spacego.OpenTagChannel(base64.RawURLEncoding.EncodeToString(metaId)) - if err := tags.Refresh(node.Cache, node.Network); err != nil { +// AllTagsForHash lists all tags for the file with the given meta ID +func (c *spaceClient) AllTagsForHash(node bcgo.Node, metaId []byte, callback spacego.TagCallback) error { + mId := base64.RawURLEncoding.EncodeToString(metaId) + tags := node.OpenChannel(spacego.TagChannelName(mId), func() bcgo.Channel { + return spacego.OpenTagChannel(mId) + }) + if err := tags.Refresh(node.Cache(), node.Network()); err != nil { log.Println(err) } - return spacego.GetTag(tags, node.Cache, node.Network, node.Alias, node.Key, nil, func(entry *bcgo.BlockEntry, tag *spacego.Tag) error { + return spacego.ReadTag(tags, node.Cache(), node.Network(), node.Account(), nil, func(entry *bcgo.BlockEntry, tag *spacego.Tag) error { for _, reference := range entry.Record.Reference { if bytes.Equal(metaId, reference.RecordHash) { callback(entry, tag) @@ -306,28 +441,32 @@ func (c *SpaceClient) GetTag(node *bcgo.Node, metaId []byte, callback func(entry }) } -// GetRegistration triggers the given callback for the most recent registration with the given merchant. -func (c *SpaceClient) GetRegistration(merchant string, callback financego.RegistrationCallback) error { - node, err := c.GetNode() +// Registration triggers the given callback for the most recent registration with the given merchant. +func (c *spaceClient) Registration(merchant string, callback financego.RegistrationCallback) error { + node, err := c.Node() if err != nil { return err } - registrations := spacego.OpenRegistrationChannel() - if err := registrations.Refresh(node.Cache, node.Network); err != nil { + registrations := node.OpenChannel(spacego.SPACE_REGISTRATION, func() bcgo.Channel { + return spacego.OpenRegistrationChannel() + }) + if err := registrations.Refresh(node.Cache(), node.Network()); err != nil { log.Println(err) } - return financego.GetRegistrationAsync(registrations, node.Cache, node.Network, merchant, nil, node.Alias, node.Key, callback) + return financego.RegistrationAsync(registrations, node.Cache(), node.Network(), node.Account(), merchant, node.Account().Alias(), callback) } -// GetSubscription triggers the given callback for the most recent subscription with the given merchant. -func (c *SpaceClient) GetSubscription(merchant string, callback financego.SubscriptionCallback) error { - node, err := c.GetNode() +// Subscription triggers the given callback for the most recent subscription with the given merchant. +func (c *spaceClient) Subscription(merchant string, callback financego.SubscriptionCallback) error { + node, err := c.Node() if err != nil { return err } - subscriptions := spacego.OpenSubscriptionChannel() - if err := subscriptions.Refresh(node.Cache, node.Network); err != nil { + subscriptions := node.OpenChannel(spacego.SPACE_SUBSCRIPTION, func() bcgo.Channel { + return spacego.OpenSubscriptionChannel() + }) + if err := subscriptions.Refresh(node.Cache(), node.Network()); err != nil { log.Println(err) } - return financego.GetSubscriptionAsync(subscriptions, node.Cache, node.Network, merchant, nil, node.Alias, node.Key, "", "", callback) + return financego.SubscriptionAsync(subscriptions, node.Cache(), node.Network(), node.Account(), merchant, node.Account().Alias(), "", "", callback) } diff --git a/vendor/aletheiaware.com/spaceclientgo/go.mod b/vendor/aletheiaware.com/spaceclientgo/go.mod index 2e9fd03..d4956f2 100644 --- a/vendor/aletheiaware.com/spaceclientgo/go.mod +++ b/vendor/aletheiaware.com/spaceclientgo/go.mod @@ -3,10 +3,12 @@ module aletheiaware.com/spaceclientgo go 1.15 require ( - aletheiaware.com/bcclientgo v1.1.4 - aletheiaware.com/bcgo v1.1.4 - aletheiaware.com/financego v1.1.3 - aletheiaware.com/spacego v1.1.4 - aletheiaware.com/testinggo v1.1.2 - github.com/golang/protobuf v1.4.3 + aletheiaware.com/aliasgo v1.2.3 + aletheiaware.com/bcclientgo v1.2.3 + aletheiaware.com/bcgo v1.2.3 + aletheiaware.com/financego v1.2.3 + aletheiaware.com/spacego v1.2.4 + aletheiaware.com/testinggo v1.2.2 + github.com/golang/protobuf v1.5.2 + github.com/stretchr/testify v1.7.0 ) diff --git a/vendor/aletheiaware.com/spaceclientgo/go.sum b/vendor/aletheiaware.com/spaceclientgo/go.sum index e848feb..64d947e 100644 --- a/vendor/aletheiaware.com/spaceclientgo/go.sum +++ b/vendor/aletheiaware.com/spaceclientgo/go.sum @@ -1,30 +1,24 @@ -aletheiaware.com/aliasgo v1.1.3 h1:RnJhpWcbH7KWWWgIvUCVS+++mzpjYNk/dQm4o1G0lX8= -aletheiaware.com/aliasgo v1.1.3/go.mod h1:JY9/j4q6ZniHb0vKO7CJJ3M03eTVhczoIIhJBZ6Sa3w= -aletheiaware.com/bcclientgo v1.1.4 h1:mSdMxH3gNDYHOwfJTwVeQwxzJsZ5Trh8Wf5K1SG4IKM= -aletheiaware.com/bcclientgo v1.1.4/go.mod h1:Ra5xSJ6fPdlcEQR4bL9wVY6PiFmlfgHl8Z0U5k3GP8Y= -aletheiaware.com/bcgo v1.1.4 h1:HuAk12UeOvtIXlc7WN2XIj9tV+jNA5uCi+D8Z0V2twU= -aletheiaware.com/bcgo v1.1.4/go.mod h1:GXvFFZ8JrATGrvuKA0J3ucf9+91eC94ggphNVpg3XUM= -aletheiaware.com/cryptogo v1.1.1 h1:XrzGXcTgYQbuL3tQv/idVzAIblb2k+o77iigiQiXTUQ= -aletheiaware.com/cryptogo v1.1.1/go.mod h1:sT8jDe5zWSIswZDAilLwfX2N6l4WOFQBm+4lYxx1Ae0= -aletheiaware.com/financego v1.1.3 h1:np43b+Vi2jK+PcjuZm97PJmtzIckhLVAHNFU5DzsKwI= -aletheiaware.com/financego v1.1.3/go.mod h1:Ht3zPGQyenlkxLXMQcKww6ctjt2bZcyLDdLz+/Koml0= -aletheiaware.com/spacego v1.1.4 h1:xhC2zG40ZAZnEVjC9UcViAHIaJEN3kXHt/iym06z6bA= -aletheiaware.com/spacego v1.1.4/go.mod h1:4tu4NMQBJaio1lNlTqKzmvGOee+EAu7crT11D0LJeCA= -aletheiaware.com/testinggo v1.1.2 h1:/zCBvslySEY4uJ2qnnyvhFdgIERa/jzlgHBOmS4lL1k= -aletheiaware.com/testinggo v1.1.2/go.mod h1:bqmrqRyMkGbTa9E/1D8xHE0KLmOw+HRG0skc/XwrdcY= +aletheiaware.com/aliasgo v1.2.3 h1:joMErbHdyo+jVbIoA9HWMPmUVfhZjabBVaB5AnYYObQ= +aletheiaware.com/aliasgo v1.2.3/go.mod h1:wSp0m2ZOXA3M3ZKFcUtcf2ANBio5JSXxQx07IpxwaGM= +aletheiaware.com/bcclientgo v1.2.3 h1:bkUjPmDCQIajTHEKveziyxq/StvBCCoOfSmwxfTqobg= +aletheiaware.com/bcclientgo v1.2.3/go.mod h1:ZUl59XyDsLGYqumzo2woBKhqVv9zjgoa/UQqFF8NPV4= +aletheiaware.com/bcgo v1.2.3 h1:5vRjjrkmlSh0/cwhY5u+0S4RUpvTCAMN1HVJMBl9A88= +aletheiaware.com/bcgo v1.2.3/go.mod h1:zNPBDrox6aUVv8ns5UOzcaDXzD/p5tZ0lGSxlfT6/Rs= +aletheiaware.com/cryptogo v1.2.2 h1:d7vEEgf3bZFnLk+HG1wCAY/pgRz+zNYvKFpxsli3Mng= +aletheiaware.com/cryptogo v1.2.2/go.mod h1:B1mJVIsfEDJoovkD2fLsZXgXxR1AAe2cDmjFwt7Eau4= +aletheiaware.com/financego v1.2.3 h1:0pDUPPSEcRbzKGR9HTvcrMQ7/anUs4EByub+yB/Unvo= +aletheiaware.com/financego v1.2.3/go.mod h1:wSeFDTfW+2OaOt5AEo8OGAfXpaQrU7+VraFxR1X5i4Q= +aletheiaware.com/spacego v1.2.4 h1:P08ld8gDaBA0cjBtsVt/hqVqQSgh/gGnrVthYy+aBWA= +aletheiaware.com/spacego v1.2.4/go.mod h1:lWj2RCxdTqwLLCbDbIhiYlO5J+nRM3RldYvLxbLwQ9w= +aletheiaware.com/testinggo v1.2.2 h1:w+ir8ehcnIcZ+jTjalGWAkh3So9PaJm5g3CPgLnPtXE= +aletheiaware.com/testinggo v1.2.2/go.mod h1:TijVTRIGnue9UHlxT9YgLp5VGWOo4PI9VRflCm4v4xo= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -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.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -32,27 +26,22 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stripe/stripe-go v70.15.0+incompatible h1:hNML7M1zx8RgtepEMlxyu/FpVPrP7KZm1gPFQquJQvM= github.com/stripe/stripe-go v70.15.0+incompatible/go.mod h1:A1dQZmO/QypXmsL0T8axYZkSN/uA/T/A64pfKdBAMiY= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc h1:+q90ECDSAQirdykUN6sPEiBXBsp8Csjcca8Oy7bgLTA= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= diff --git a/vendor/aletheiaware.com/spacefynego/README.md b/vendor/aletheiaware.com/spacefynego/README.md new file mode 100644 index 0000000..1cc6043 --- /dev/null +++ b/vendor/aletheiaware.com/spacefynego/README.md @@ -0,0 +1,19 @@ +spacefynego +=========== + +This is a Go implementation of a S P A C E client - secure, private, storage. + +# About + +`spacefynego` provides a graphical user interface built with the [Fyne](https://fyne.io) toolkit to explore and interact with S P A C E. + +# Build + + go build -tags release + +# Install + +Install the application (or download from https://github.com/AletheiaWareLLC/spacefynego/releases/latest) + + go get fyne.io/fyne + fyne get aletheiaware.com/spacefynego/cmd/spacefyne diff --git a/vendor/aletheiaware.com/spacefynego/fyne.go b/vendor/aletheiaware.com/spacefynego/fyne.go index a474069..08ae897 100644 --- a/vendor/aletheiaware.com/spacefynego/fyne.go +++ b/vendor/aletheiaware.com/spacefynego/fyne.go @@ -21,6 +21,7 @@ import ( bcstorage "aletheiaware.com/bcfynego/storage" bcui "aletheiaware.com/bcfynego/ui" "aletheiaware.com/bcgo" + "aletheiaware.com/bcgo/network" "aletheiaware.com/financego" "aletheiaware.com/spaceclientgo" "aletheiaware.com/spacefynego/storage" @@ -28,6 +29,8 @@ import ( "aletheiaware.com/spacefynego/ui/data" "aletheiaware.com/spacefynego/ui/viewer" "aletheiaware.com/spacego" + "bytes" + "context" "encoding/base64" "errors" "fmt" @@ -38,193 +41,243 @@ import ( fynestorage "fyne.io/fyne/v2/storage" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" + "image/color" + "io" + "io/ioutil" "log" "net/url" + "reflect" "strings" ) -type SpaceFyne struct { +const preferenceDisableMinimumRegistrarWarning = "%s_disable_minimum_registrar_warning" + +type SpaceFyne interface { + bcfynego.BCFyne + + Add(spaceclientgo.SpaceClient) + SearchFile(spaceclientgo.SpaceClient) + ShowComposeTextDialog(spaceclientgo.SpaceClient, bcgo.Node) + ShowFile(spaceclientgo.SpaceClient, string, uint64, *spacego.Meta) + ShowHelp(spaceclientgo.SpaceClient) + ShowRegistrarDialog(spaceclientgo.SpaceClient, bcgo.Node) func(string, uint64, *spacego.Registrar, *financego.Registration, *financego.Subscription) + ShowRegistrarSelectionDialog(spaceclientgo.SpaceClient, bcgo.Node) + ShowStorage(spaceclientgo.SpaceClient) + ShowUploadFileDialog(spaceclientgo.SpaceClient, bcgo.Node) + ShowUploadFolderDialog(spaceclientgo.SpaceClient, bcgo.Node) + ShowWelcome(spaceclientgo.SpaceClient, bcgo.Node) + UploadFile(spaceclientgo.SpaceClient, bcgo.Node, string, string, io.Reader) + UploadFolder(spaceclientgo.SpaceClient, bcgo.Node, fyne.ListableURI) +} + +type spaceFyne struct { bcfynego.BCFyne } -func NewSpaceFyne(a fyne.App, w fyne.Window, c *spaceclientgo.SpaceClient) *SpaceFyne { - f := &SpaceFyne{ - BCFyne: *bcfynego.NewBCFyne(a, w), +func NewSpaceFyne(a fyne.App, w fyne.Window, c spaceclientgo.SpaceClient) SpaceFyne { + f := &spaceFyne{ + BCFyne: bcfynego.NewBCFyne(a, w), } - f.OnSignedIn = func(node *bcgo.Node) { + f.AddOnSignedIn(func(account bcgo.Account) { + node, err := f.Node(c) + if err != nil { + f.ShowError(err) + return + } // Create BC Repository - bcstorage.NewBCRepository(&c.BCClient).Register() + bcstorage.NewBCRepository(c).Register() // Create Space Repository storage.NewSpaceRepository(c, node).Register() count := 0 - if err := spacego.GetAllSubscriptionsForNode(node, func(*bcgo.BlockEntry, *financego.Subscription) error { + if err := spacego.AllSubscriptionsForNode(node, func(*bcgo.BlockEntry, *financego.Subscription) error { count++ return nil }); err != nil { log.Println(err) } - if count < spacego.GetMinimumRegistrars() { - f.ShowRegistrarSelectionDialog(c, node) + if min := spacego.MinimumRegistrars(); count < min { + preference := fmt.Sprintf(preferenceDisableMinimumRegistrarWarning, account.Alias()) + preferences := a.Preferences() + if !preferences.Bool(preference) { + label := &widget.Label{ + Text: fmt.Sprintf("Your data is currently stored on %d registrar(s). We recommend choosing at least %d registrars to store your backups and ensure your data's resilience.", count, min), + Wrapping: fyne.TextWrapWord, + } + disable := widget.NewCheck("Dont remind me again", func(checked bool) { + preferences.SetBool(preference, checked) + }) + + contents := container.NewVBox() + if !bcgo.IsLive() { + contents.Add(bcui.NewTestModeSign()) + } + contents.Add(label) + contents.Add(disable) + confirm := dialog.NewCustomConfirm("Registrars", "Next", "Cancel", contents, + func(result bool) { + if result { + f.ShowRegistrarSelectionDialog(c, node) + } + }, + f.Window()) + confirm.Show() + confirm.Resize(bcui.DialogSize) + } + } + }) + f.AddOnSignedUp(func(bcgo.Account) { + node, err := f.Node(c) + if err != nil { + f.ShowError(err) + return } - } - f.OnSignedUp = func(node *bcgo.Node) { f.ShowWelcome(c, node) - } + }) return f } // ShowWelcome displays a wizard to welcome a new user and walk them through the setup process. -func (f *SpaceFyne) ShowWelcome(client *spaceclientgo.SpaceClient, node *bcgo.Node) { - if d := f.Dialog; d != nil { - d.Hide() +func (f spaceFyne) ShowWelcome(client spaceclientgo.SpaceClient, node bcgo.Node) { + contents := container.NewVBox() + if !bcgo.IsLive() { + contents.Add(bcui.NewTestModeSign()) } - f.Dialog = dialog.NewCustomConfirm("Welcome", "Next", "Cancel", - widget.NewLabel(fmt.Sprintf("Hello %s, Welcome to S P A C E!", node.Alias)), + contents.Add(widget.NewLabel(fmt.Sprintf("Hello %s, Welcome to S P A C E!", node.Account().Alias()))) + dialog := dialog.NewCustomConfirm("Welcome", "Next", "Cancel", + contents, func(result bool) { if result { f.ShowRegistrarSelectionDialog(client, node) } }, - f.Window) - f.Dialog.Show() - f.Dialog.Resize(bcui.DialogSize) + f.Window()) + dialog.Show() + dialog.Resize(bcui.DialogSize) } -func (f *SpaceFyne) ShowRegistrarSelectionDialog(client *spaceclientgo.SpaceClient, node *bcgo.Node) { - if d := f.Dialog; d != nil { - d.Hide() - } - +func (f spaceFyne) ShowRegistrarSelectionDialog(client spaceclientgo.SpaceClient, node bcgo.Node) { // Show progress dialog - f.Dialog = dialog.NewProgressInfinite("Updating", "Getting Registrars", f.Window) - f.Dialog.Show() + progress := dialog.NewProgressInfinite("Updating", "Getting Registrars", f.Window()) + progress.Show() - l := ui.NewRegistrarList(f.ShowRegistrarDialog(client, node)) + list := ui.NewRegistrarList(f.ShowRegistrarDialog(client, node)) // Update list - l.Update(client, node) + err := list.Update(client, node) + + // Hide progress dialog + progress.Hide() - if d := f.Dialog; d != nil { - d.Hide() + if err != nil { + f.ShowError(fmt.Errorf("Error updating registrar list: %s", err)) + return + } + contents := container.NewVBox() + if !bcgo.IsLive() { + contents.Add(bcui.NewTestModeSign()) } - f.Dialog = dialog.NewCustom("Registrars", "Done", - container.NewBorder( - &widget.Label{ - Text: fmt.Sprintf("Your encrypted data will be stored by your choice of storage providers.\nWe recommend choosing at least %d registrars from the list below - the more you choose, the more resilient your data will be against the unexpected.", spacego.GetMinimumRegistrars()), - Wrapping: fyne.TextWrapWord, - }, - nil, - nil, - nil, - l, - ), - f.Window) - f.Dialog.Show() - f.Dialog.Resize(bcui.DialogSize) + contents.Add(container.NewBorder( + &widget.Label{ + Text: fmt.Sprintf("Your encrypted data will be stored by your choice of storage providers.\nWe recommend choosing at least %d registrars from the list below - the more you choose, the more resilient your data will be against the unexpected.", spacego.MinimumRegistrars()), + Wrapping: fyne.TextWrapWord, + }, + nil, + nil, + nil, + list, + )) + + dialog := dialog.NewCustom("Registrars", "Done", contents, f.Window()) + dialog.Show() + dialog.Resize(bcui.DialogSize) } -func (f *SpaceFyne) GetIcon() fyne.CanvasObject { +func (f spaceFyne) GetIcon() fyne.CanvasObject { icon := canvas.NewImageFromResource(data.SpaceIcon) icon.FillMode = canvas.ImageFillContain return icon } // Add displays a dialog (write text, take a picture, upload an existing file or folder), and adds the result. -func (f *SpaceFyne) Add(client *spaceclientgo.SpaceClient) { - node, err := f.GetNode(&client.BCClient) +func (f spaceFyne) Add(client spaceclientgo.SpaceClient) { + node, err := f.Node(client) if err != nil { f.ShowError(err) return } - if d := f.Dialog; d != nil { - d.Hide() - } // Show progress dialog - f.Dialog = dialog.NewProgressInfinite("Updating", "Getting Registrars", f.Window) - f.Dialog.Show() + progress := dialog.NewProgressInfinite("Updating", "Getting Registrars", f.Window()) + progress.Show() - domains, err := f.getRegistrarDomainsForNode(client, node) + domains, err := f.registrarDomainsForNode(client, node) if err != nil { log.Println(err) } + // Hide progress dialog + progress.Hide() + if len(domains) == 0 { f.ShowRegistrarSelectionDialog(client, node) return } + content := container.NewAdaptiveGrid(3) + dialog := dialog.NewCustom("Add", "Cancel", content, f.Window()) + dialog.Show() - if d := f.Dialog; d != nil { - d.Hide() - } composeText := widget.NewButtonWithIcon("Text", theme.DocumentCreateIcon(), func() { - if d := f.Dialog; d != nil { - d.Hide() - } + dialog.Hide() f.ShowComposeTextDialog(client, node) }) captureImage := widget.NewButtonWithIcon("Image", theme.NewThemedResource(data.CameraPhotoIcon), func() { - if d := f.Dialog; d != nil { - d.Hide() - } + dialog.Hide() // TODO f.ShowError(fmt.Errorf("Not yet implemented: %s %s", "SpaceFyne.Add", "Image")) }) captureVideo := widget.NewButtonWithIcon("Video", theme.NewThemedResource(data.CameraVideoIcon), func() { - if d := f.Dialog; d != nil { - d.Hide() - } + dialog.Hide() // TODO f.ShowError(fmt.Errorf("Not yet implemented: %s %s", "SpaceFyne.Add", "Video")) }) captureAudio := widget.NewButtonWithIcon("Audio", theme.NewThemedResource(data.MicrophoneIcon), func() { - if d := f.Dialog; d != nil { - d.Hide() - } + dialog.Hide() // TODO f.ShowError(fmt.Errorf("Not yet implemented: %s %s", "SpaceFyne.Add", "Audio")) }) uploadFile := widget.NewButtonWithIcon("Document", theme.FileIcon(), func() { - if d := f.Dialog; d != nil { - d.Hide() - } + dialog.Hide() go f.ShowUploadFileDialog(client, node) }) uploadFolder := widget.NewButtonWithIcon("Directory", theme.FolderIcon(), func() { - if d := f.Dialog; d != nil { - d.Hide() - } + dialog.Hide() go f.ShowUploadFolderDialog(client, node) }) - content := container.NewAdaptiveGrid(3, + content.Objects = []fyne.CanvasObject{ composeText, captureImage, captureAudio, captureVideo, uploadFile, uploadFolder, - ) - if d := f.Dialog; d != nil { - d.Hide() } - f.Dialog = dialog.NewCustom("Add", "Cancel", content, f.Window) - f.Dialog.Show() } -func (f *SpaceFyne) SearchFile(client *spaceclientgo.SpaceClient) { +func (f spaceFyne) SearchFile(client spaceclientgo.SpaceClient) { f.ShowError(fmt.Errorf("Not yet implemented: %s", "SpaceFyne.SearchFile")) } -func (f *SpaceFyne) ShowFile(client *spaceclientgo.SpaceClient, id string, timestamp uint64, meta *spacego.Meta) { - node, err := f.GetNode(&client.BCClient) +func (f spaceFyne) ShowFile(client spaceclientgo.SpaceClient, id string, timestamp uint64, meta *spacego.Meta) { + node, err := f.Node(client) if err != nil { f.ShowError(err) return } // Show progress dialog - progress := dialog.NewProgressInfinite("Loading", "Reading "+meta.Name, f.Window) + progress := dialog.NewProgressInfinite("Loading", "Reading "+meta.Name, f.Window()) progress.Show() + // Hide progress dialog defer progress.Hide() hash, err := base64.RawURLEncoding.DecodeString(id) @@ -233,58 +286,80 @@ func (f *SpaceFyne) ShowFile(client *spaceclientgo.SpaceClient, id string, times return } - reader, err := client.ReadFile(node, hash) + view, err := viewer.ForMime(meta.Type) if err != nil { f.ShowError(err) return } - - view := viewer.GetViewer(meta, reader) if view == nil { f.ShowError(fmt.Errorf("Not yet implemented: %s %s", "SpaceFyne.ShowFile", meta.Type)) return } + ctx, cancel := context.WithCancel(context.Background()) + + client.WatchFile(ctx, node, hash, func() { + reader, err := client.ReadFile(node, hash) + if err != nil { + f.ShowError(err) + return + } + if err := view.SetSource(reader); err != nil { + f.ShowError(err) + return + } + }) + name := meta.Name if name == "" { name = "(untitled)" } - window := f.App.NewWindow(fmt.Sprintf("%s - %s - %s", bcgo.TimestampToString(timestamp), name, id[:8])) + window := f.App().NewWindow(fmt.Sprintf("%s - %s - %s", bcgo.TimestampToString(timestamp), name, id[:8])) window.SetContent(view) window.Resize(bcui.WindowSize) window.CenterOnScreen() + window.SetOnClosed(cancel) window.Show() } -func (f *SpaceFyne) ShowStorage(client *spaceclientgo.SpaceClient) { - node, err := f.GetNode(&client.BCClient) +func (f spaceFyne) ShowStorage(client spaceclientgo.SpaceClient) { + node, err := f.Node(client) if err != nil { f.ShowError(err) return } // Show progress dialog - progress := dialog.NewProgressInfinite("Updating", "Getting Registrars", f.Window) + progress := dialog.NewProgressInfinite("Updating", "Getting Registrars", f.Window()) progress.Show() list := ui.NewRegistrarList(f.ShowRegistrarDialog(client, node)) // Update list - list.Update(client, node) + err = list.Update(client, node) // Hide progress dialog progress.Hide() - if d := f.Dialog; d != nil { - d.Hide() + if err != nil { + f.ShowError(fmt.Errorf("Error updating registrar list: %s", err)) + return + } + + contents := container.NewVBox() + if !bcgo.IsLive() { + contents.Add(bcui.NewTestModeSign()) } + contents.Add(list) + // Show registrar list - f.Dialog = dialog.NewCustom("Registrars", "OK", list, f.Window) - f.Dialog.Show() - f.Dialog.Resize(bcui.DialogSize) + dialog := dialog.NewCustom("Registrars", "OK", contents, f.Window()) + dialog.Show() + dialog.Resize(bcui.DialogSize) } -func (f *SpaceFyne) ShowRegistrarDialog(client *spaceclientgo.SpaceClient, node *bcgo.Node) func(id string, timestamp uint64, registrar *spacego.Registrar, registration *financego.Registration, subscription *financego.Subscription) { +func (f spaceFyne) ShowRegistrarDialog(client spaceclientgo.SpaceClient, node bcgo.Node) func(id string, timestamp uint64, registrar *spacego.Registrar, registration *financego.Registration, subscription *financego.Subscription) { + alias := node.Account().Alias() return func(id string, timestamp uint64, registrar *spacego.Registrar, registration *financego.Registration, subscription *financego.Subscription) { form := widget.NewForm( widget.NewFormItem("Domain", &widget.Label{ @@ -313,10 +388,10 @@ func (f *SpaceFyne) ShowRegistrarDialog(client *spaceclientgo.SpaceClient, node return } params := url.Values{} - params.Add("alias", node.Alias) + params.Add("alias", alias) params.Add("next", registrar.Service.SubscribeUrl) u.RawQuery = params.Encode() - if err := f.App.OpenURL(u); err != nil { + if err := f.App().OpenURL(u); err != nil { f.ShowError(err) return } @@ -343,29 +418,34 @@ func (f *SpaceFyne) ShowRegistrarDialog(client *spaceclientgo.SpaceClient, node return } params := url.Values{} - params.Add("alias", node.Alias) + params.Add("alias", alias) params.Add("customerId", registration.CustomerId) u.RawQuery = params.Encode() - if err := f.App.OpenURL(u); err != nil { + if err := f.App().OpenURL(u); err != nil { f.ShowError(err) return } })) } + contents := container.NewVBox() + if !bcgo.IsLive() { + contents.Add(bcui.NewTestModeSign()) + } + contents.Add(form) // Show detailed information - info := dialog.NewCustom(registrar.Merchant.Alias, "OK", form, f.Window) + info := dialog.NewCustom(registrar.Merchant.Alias, "OK", contents, f.Window()) info.Show() info.Resize(bcui.DialogSize) } } -func (f *SpaceFyne) ShowHelp(client *spaceclientgo.SpaceClient) { +func (f spaceFyne) ShowHelp(client spaceclientgo.SpaceClient) { f.ShowError(fmt.Errorf("Not yet implemented: %s", "SpaceFyne.ShowHelp")) } // ShowComposeTextDialog displays a dialog for creating a note, and adds the resulting file. -func (f *SpaceFyne) ShowComposeTextDialog(client *spaceclientgo.SpaceClient, node *bcgo.Node) { +func (f spaceFyne) ShowComposeTextDialog(client spaceclientgo.SpaceClient, node bcgo.Node) { title := widget.NewEntry() title.Validator = func(s string) error { if s == "" { @@ -378,32 +458,35 @@ func (f *SpaceFyne) ShowComposeTextDialog(client *spaceclientgo.SpaceClient, nod widget.NewFormItem("Title", title), widget.NewFormItem("Content", content), } - f.Dialog = dialog.NewForm("Compose", "Save", "Cancel", items, func(b bool) { + dialog := dialog.NewForm("Compose", "Save", "Cancel", items, func(b bool) { if !b { return } name := title.Text // Show progress dialog - progress := dialog.NewProgress("Uploading", "Uploading "+name, f.Window) + progress := dialog.NewProgress("Uploading", "Uploading "+name, f.Window()) progress.Show() - defer progress.Hide() listener := &bcui.ProgressMiningListener{Func: progress.SetValue} reference, err := client.Add(node, listener, name, spacego.MIME_TYPE_TEXT_PLAIN, strings.NewReader(content.Text)) + + // Hide progress dialog + progress.Hide() + if err != nil { f.ShowError(err) return } log.Println("Uploaded:", reference) - }, f.Window) - f.Dialog.Show() - f.Dialog.Resize(bcui.DialogSize) + }, f.Window()) + dialog.Show() + dialog.Resize(bcui.DialogSize) } // ShowUploadFileDialog displays a file picker, and adds the resulting file. -func (f *SpaceFyne) ShowUploadFileDialog(client *spaceclientgo.SpaceClient, node *bcgo.Node) { - f.Dialog = dialog.NewFileOpen(func(reader fyne.URIReadCloser, err error) { +func (f spaceFyne) ShowUploadFileDialog(client spaceclientgo.SpaceClient, node bcgo.Node) { + dialog := dialog.NewFileOpen(func(reader fyne.URIReadCloser, err error) { if err != nil { f.ShowError(err) return @@ -411,15 +494,67 @@ func (f *SpaceFyne) ShowUploadFileDialog(client *spaceclientgo.SpaceClient, node if reader == nil { return } - f.UploadFile(client, node, reader) - }, f.Window) - f.Dialog.Show() - f.Dialog.Resize(bcui.DialogSize) + + // Show confirmation dialog so user can see preview and change name, mime, etc. + uri := reader.URI() + name := widget.NewEntry() + name.SetText(uri.Name()) + mime := widget.NewSelect(spacego.MimeTypes(), nil) + mime.Selected = uri.MimeType() + size := widget.NewLabel("0bytes") + prop := canvas.NewRectangle(color.Transparent) + prop.SetMinSize(fyne.NewSize(200, 200)) + noPreview := widget.NewLabel("No Preview") + preview := container.NewMax(prop, noPreview) + form := widget.NewForm( + widget.NewFormItem("Name", name), + widget.NewFormItem("Type", mime), + widget.NewFormItem("Size", size), + widget.NewFormItem("Preview", preview), + ) + + var buffer []byte + loadPreview := func(mime string) { + if view, err := viewer.ForMime(mime); err != nil || view == nil { + preview.Objects[1] = noPreview + } else { + preview.Objects[1] = view + // Load file contents and update viewer + if err := view.SetSource(bytes.NewReader(buffer)); err != nil { + log.Println(err) + } + } + form.Refresh() + } + mime.OnChanged = func(mime string) { + go loadPreview(mime) + } + + go func() { + buffer, err = ioutil.ReadAll(reader) + if err != nil { + f.ShowError(err) + return + } + size.SetText(bcgo.BinarySizeToString(uint64(len(buffer)))) + loadPreview(mime.Selected) + }() + + dialog := dialog.NewCustomConfirm("Upload File", "Upload", "Cancel", form, func(result bool) { + if result { + f.UploadFile(client, node, name.Text, mime.Selected, bytes.NewReader(buffer)) + } + }, f.Window()) + dialog.Show() + dialog.Resize(bcui.DialogSize) + }, f.Window()) + dialog.Show() + dialog.Resize(bcui.DialogSize) } // ShowUploadFolderDialog displays a folder picker, and adds the resulting folder. -func (f *SpaceFyne) ShowUploadFolderDialog(client *spaceclientgo.SpaceClient, node *bcgo.Node) { - f.Dialog = dialog.NewFolderOpen(func(lister fyne.ListableURI, err error) { +func (f spaceFyne) ShowUploadFolderDialog(client spaceclientgo.SpaceClient, node bcgo.Node) { + dialog := dialog.NewFolderOpen(func(lister fyne.ListableURI, err error) { if err != nil { f.ShowError(err) return @@ -428,20 +563,22 @@ func (f *SpaceFyne) ShowUploadFolderDialog(client *spaceclientgo.SpaceClient, no return } f.UploadFolder(client, node, lister) - }, f.Window) - f.Dialog.Show() - f.Dialog.Resize(bcui.DialogSize) + }, f.Window()) + dialog.Show() + dialog.Resize(bcui.DialogSize) } -func (f *SpaceFyne) UploadFile(client *spaceclientgo.SpaceClient, node *bcgo.Node, file fyne.URIReadCloser) { - name := file.URI().Name() +func (f spaceFyne) UploadFile(client spaceclientgo.SpaceClient, node bcgo.Node, name, mime string, reader io.Reader) { // Show progress dialog - progress := dialog.NewProgress("Uploading", "Uploading "+name, f.Window) + progress := dialog.NewProgress("Uploading", "Uploading "+name, f.Window()) progress.Show() - defer progress.Hide() listener := &bcui.ProgressMiningListener{Func: progress.SetValue} - reference, err := client.Add(node, listener, name, file.URI().MimeType(), file) + reference, err := client.Add(node, listener, name, mime, reader) + + // Hide progress dialog + progress.Hide() + if err != nil { f.ShowError(err) return @@ -449,7 +586,7 @@ func (f *SpaceFyne) UploadFile(client *spaceclientgo.SpaceClient, node *bcgo.Nod log.Println("Uploaded:", reference) } -func (f *SpaceFyne) UploadFolder(client *spaceclientgo.SpaceClient, node *bcgo.Node, folder fyne.ListableURI) { +func (f spaceFyne) UploadFolder(client spaceclientgo.SpaceClient, node bcgo.Node, folder fyne.ListableURI) { uris, err := folder.List() if err != nil { f.ShowError(err) @@ -457,9 +594,12 @@ func (f *SpaceFyne) UploadFolder(client *spaceclientgo.SpaceClient, node *bcgo.N } count := len(uris) + // TODO show confirmation dialog which lists the files to be uploaded so the user can select/deselect + // Show progress dialog - progress := dialog.NewProgress("Uploading", "Uploading "+folder.Name(), f.Window) + progress := dialog.NewProgress("Uploading", "Uploading "+folder.Name(), f.Window()) progress.Show() + // Hide progress dialog defer progress.Hide() for i, uri := range uris { @@ -482,28 +622,25 @@ func (f *SpaceFyne) UploadFolder(client *spaceclientgo.SpaceClient, node *bcgo.N log.Println(err) continue } - f.UploadFile(client, node, file) + f.UploadFile(client, node, uri.Name(), uri.MimeType(), file) } } -func (f *SpaceFyne) getRegistrarDomainsForNode(client *spaceclientgo.SpaceClient, node *bcgo.Node) (domains []string, err error) { - var net *bcgo.TCPNetwork - if node.Network != nil { - if n, ok := node.Network.(*bcgo.TCPNetwork); ok { - net = n +func (f spaceFyne) registrarDomainsForNode(client spaceclientgo.SpaceClient, node bcgo.Node) (domains []string, err error) { + var tcp *network.TCP + if n := node.Network(); n != nil && !reflect.ValueOf(n).IsNil() { + if t, ok := n.(*network.TCP); ok { + tcp = t } } - err = spacego.GetAllRegistrarsForNode(node, func(registrar *spacego.Registrar, registration *financego.Registration, subscription *financego.Subscription) error { + err = spacego.AllRegistrarsForNode(node, func(registrar *spacego.Registrar, registration *financego.Registration, subscription *financego.Subscription) error { if registrar != nil && registration != nil && subscription != nil { domain := registrar.Merchant.Domain if domain == "" { domain = registrar.Merchant.Alias } - // Add any missing domains to network - if net != nil { - if _, ok := net.Peers[domain]; !ok { - net.Peers[domain] = 0 - } + if tcp != nil { + tcp.AddPeer(domain) } domains = append(domains, domain) } diff --git a/vendor/aletheiaware.com/spacefynego/go.mod b/vendor/aletheiaware.com/spacefynego/go.mod index b875422..0286d93 100644 --- a/vendor/aletheiaware.com/spacefynego/go.mod +++ b/vendor/aletheiaware.com/spacefynego/go.mod @@ -3,10 +3,12 @@ module aletheiaware.com/spacefynego go 1.15 require ( - aletheiaware.com/bcfynego v1.1.7 - aletheiaware.com/bcgo v1.1.4 - aletheiaware.com/financego v1.1.3 - aletheiaware.com/spaceclientgo v1.1.5 - aletheiaware.com/spacego v1.1.4 - fyne.io/fyne/v2 v2.0.0 + aletheiaware.com/bcfynego v1.2.3 + aletheiaware.com/bcgo v1.2.3 + aletheiaware.com/financego v1.2.3 + aletheiaware.com/spaceclientgo v1.2.4 + aletheiaware.com/spacego v1.2.4 + aletheiaware.com/testinggo v1.2.2 + fyne.io/fyne/v2 v2.0.2 + github.com/stretchr/testify v1.7.0 ) diff --git a/vendor/aletheiaware.com/spacefynego/go.sum b/vendor/aletheiaware.com/spacefynego/go.sum index 6b94e40..c9d6881 100644 --- a/vendor/aletheiaware.com/spacefynego/go.sum +++ b/vendor/aletheiaware.com/spacefynego/go.sum @@ -1,23 +1,23 @@ -aletheiaware.com/aliasgo v1.1.3 h1:RnJhpWcbH7KWWWgIvUCVS+++mzpjYNk/dQm4o1G0lX8= -aletheiaware.com/aliasgo v1.1.3/go.mod h1:JY9/j4q6ZniHb0vKO7CJJ3M03eTVhczoIIhJBZ6Sa3w= -aletheiaware.com/bcclientgo v1.1.4 h1:mSdMxH3gNDYHOwfJTwVeQwxzJsZ5Trh8Wf5K1SG4IKM= -aletheiaware.com/bcclientgo v1.1.4/go.mod h1:Ra5xSJ6fPdlcEQR4bL9wVY6PiFmlfgHl8Z0U5k3GP8Y= -aletheiaware.com/bcfynego v1.1.7 h1:HV0GxLPumBg/HM95QWGsbMlVlKU5W81Qa80nOBK69x4= -aletheiaware.com/bcfynego v1.1.7/go.mod h1:T+Eb2fCbwpSTumyzf2WTG+kkqE6lEofSqnyRV0SKsIE= -aletheiaware.com/bcgo v1.1.4 h1:HuAk12UeOvtIXlc7WN2XIj9tV+jNA5uCi+D8Z0V2twU= -aletheiaware.com/bcgo v1.1.4/go.mod h1:GXvFFZ8JrATGrvuKA0J3ucf9+91eC94ggphNVpg3XUM= -aletheiaware.com/cryptogo v1.1.1 h1:XrzGXcTgYQbuL3tQv/idVzAIblb2k+o77iigiQiXTUQ= -aletheiaware.com/cryptogo v1.1.1/go.mod h1:sT8jDe5zWSIswZDAilLwfX2N6l4WOFQBm+4lYxx1Ae0= -aletheiaware.com/financego v1.1.3 h1:np43b+Vi2jK+PcjuZm97PJmtzIckhLVAHNFU5DzsKwI= -aletheiaware.com/financego v1.1.3/go.mod h1:Ht3zPGQyenlkxLXMQcKww6ctjt2bZcyLDdLz+/Koml0= -aletheiaware.com/spaceclientgo v1.1.5 h1:hR9z48oYpa88gU0ewgnZyPZLuSrjbwideABHKwK+t6Q= -aletheiaware.com/spaceclientgo v1.1.5/go.mod h1:9UhWgzhaDr2HGyoSuNSefa6bukH+BQDC8veDkZo5XQw= -aletheiaware.com/spacego v1.1.4 h1:xhC2zG40ZAZnEVjC9UcViAHIaJEN3kXHt/iym06z6bA= -aletheiaware.com/spacego v1.1.4/go.mod h1:4tu4NMQBJaio1lNlTqKzmvGOee+EAu7crT11D0LJeCA= -aletheiaware.com/testinggo v1.1.2 h1:/zCBvslySEY4uJ2qnnyvhFdgIERa/jzlgHBOmS4lL1k= -aletheiaware.com/testinggo v1.1.2/go.mod h1:bqmrqRyMkGbTa9E/1D8xHE0KLmOw+HRG0skc/XwrdcY= -fyne.io/fyne/v2 v2.0.0 h1:TfsS3bNq5663BpXsoz1OfzyjcaMqqOf9usI8ZKkw4IE= -fyne.io/fyne/v2 v2.0.0/go.mod h1:FmobqvPpBW+nG1nDyxZWf1SQLED9g/vXIxiIIVjHazY= +aletheiaware.com/aliasgo v1.2.3 h1:joMErbHdyo+jVbIoA9HWMPmUVfhZjabBVaB5AnYYObQ= +aletheiaware.com/aliasgo v1.2.3/go.mod h1:wSp0m2ZOXA3M3ZKFcUtcf2ANBio5JSXxQx07IpxwaGM= +aletheiaware.com/bcclientgo v1.2.3 h1:bkUjPmDCQIajTHEKveziyxq/StvBCCoOfSmwxfTqobg= +aletheiaware.com/bcclientgo v1.2.3/go.mod h1:ZUl59XyDsLGYqumzo2woBKhqVv9zjgoa/UQqFF8NPV4= +aletheiaware.com/bcfynego v1.2.3 h1:e8/UByeMavPyseR83Loo6LOEW8cR6ezgLXArduxH5zI= +aletheiaware.com/bcfynego v1.2.3/go.mod h1:5wYg/kMnceZQWescJTUZ9lT4ob3WOMn1/6ECx5VYT3o= +aletheiaware.com/bcgo v1.2.3 h1:5vRjjrkmlSh0/cwhY5u+0S4RUpvTCAMN1HVJMBl9A88= +aletheiaware.com/bcgo v1.2.3/go.mod h1:zNPBDrox6aUVv8ns5UOzcaDXzD/p5tZ0lGSxlfT6/Rs= +aletheiaware.com/cryptogo v1.2.2 h1:d7vEEgf3bZFnLk+HG1wCAY/pgRz+zNYvKFpxsli3Mng= +aletheiaware.com/cryptogo v1.2.2/go.mod h1:B1mJVIsfEDJoovkD2fLsZXgXxR1AAe2cDmjFwt7Eau4= +aletheiaware.com/financego v1.2.3 h1:0pDUPPSEcRbzKGR9HTvcrMQ7/anUs4EByub+yB/Unvo= +aletheiaware.com/financego v1.2.3/go.mod h1:wSeFDTfW+2OaOt5AEo8OGAfXpaQrU7+VraFxR1X5i4Q= +aletheiaware.com/spaceclientgo v1.2.4 h1:6CwANEdUBXSuNu9moFj82Loh5idi4O3CPW6OVTaDJhA= +aletheiaware.com/spaceclientgo v1.2.4/go.mod h1:jW1BWXiBS23Gwj354+BHZH+ojChQ/fzURgMHuE80ZO8= +aletheiaware.com/spacego v1.2.4 h1:P08ld8gDaBA0cjBtsVt/hqVqQSgh/gGnrVthYy+aBWA= +aletheiaware.com/spacego v1.2.4/go.mod h1:lWj2RCxdTqwLLCbDbIhiYlO5J+nRM3RldYvLxbLwQ9w= +aletheiaware.com/testinggo v1.2.2 h1:w+ir8ehcnIcZ+jTjalGWAkh3So9PaJm5g3CPgLnPtXE= +aletheiaware.com/testinggo v1.2.2/go.mod h1:TijVTRIGnue9UHlxT9YgLp5VGWOo4PI9VRflCm4v4xo= +fyne.io/fyne/v2 v2.0.2 h1:6pDvFuCmL1odyT/fPI+2L54hMJW1Zt9Dno41HmLInRs= +fyne.io/fyne/v2 v2.0.2/go.mod h1:3+FYmLJVgeb8EvTPJ5YzZeo7LkAq4bbuY3Zrir6xHbg= github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9 h1:1ltqoej5GtaWF8jaiA49HwsZD459jqm9YFz9ZtMFpQA= github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I= github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw= @@ -29,27 +29,21 @@ github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8 github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fyne-io/mobile v0.1.2 h1:0HaXDtOOwyOTn3Umi0uKVCOgJtfX73c6unC4U8i5VZU= -github.com/fyne-io/mobile v0.1.2/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY= +github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f h1:rguJ/t99j/6zRSFzsBKlsmmyl+vOvCeTJ+2uTBvuXFI= +github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY= github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw= github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3 h1:q521PfSp5/z6/sD9FZZOWj4d1MLmfQW8PkRnI9M6PCE= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48 h1:QrUfZrT8n72FUuiABt4tbu8PwDnOPAbnj3Mql1UhdRI= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8= github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw= -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.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526 h1:NfuKjkj/Xc2z1xZIj+EmNCm5p1nKJPyw3F4E20usXvg= github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc= github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca h1:ozPUX9TKQZVek4lZWYRsQo7uS8vJ+q4OOHvRhHiCLfU= @@ -57,7 +51,6 @@ github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mo github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lucor/goinfo v0.0.0-20200401173949-526b5363a13a h1:4djPngMU3ttoFCf6DOgPNQYmxyNmRRmpLg4/uz2TTEg= github.com/lucor/goinfo v0.0.0-20200401173949-526b5363a13a/go.mod h1:ORP3/rB5IsulLEBwQZCJyyV6niqmI7P4EWSmkug+1Ng= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= @@ -85,8 +78,8 @@ github.com/stripe/stripe-go v70.15.0+incompatible/go.mod h1:A1dQZmO/QypXmsL0T8ax github.com/yuin/goldmark v1.1.25/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-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc h1:+q90ECDSAQirdykUN6sPEiBXBsp8Csjcca8Oy7bgLTA= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -97,20 +90,25 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666 h1:gVCS+QOncANNPlmlO1AhlU3oxs4V9z+gTtPwIk3p2N8= golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +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.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -120,13 +118,9 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/vendor/aletheiaware.com/spacefynego/storage/repository.go b/vendor/aletheiaware.com/spacefynego/storage/repository.go index 84a736f..9b373cc 100644 --- a/vendor/aletheiaware.com/spacefynego/storage/repository.go +++ b/vendor/aletheiaware.com/spacefynego/storage/repository.go @@ -41,19 +41,19 @@ type SpaceRepository interface { Register() } -type spacerepo struct { - client *spaceclientgo.SpaceClient - node *bcgo.Node +type spaceRepository struct { + client spaceclientgo.SpaceClient + node bcgo.Node } -func NewSpaceRepository(client *spaceclientgo.SpaceClient, node *bcgo.Node) SpaceRepository { - return &spacerepo{ +func NewSpaceRepository(client spaceclientgo.SpaceClient, node bcgo.Node) SpaceRepository { + return &spaceRepository{ client: client, node: node, } } -func (r *spacerepo) CanList(u fyne.URI) (bool, error) { +func (r *spaceRepository) CanList(u fyne.URI) (bool, error) { if u == RootURI { return true, nil } @@ -61,7 +61,7 @@ func (r *spacerepo) CanList(u fyne.URI) (bool, error) { return false, fmt.Errorf("%s: Not Yet Implemented", "SpaceRepository.CanList") } -func (r *spacerepo) CanRead(u fyne.URI) (bool, error) { +func (r *spaceRepository) CanRead(u fyne.URI) (bool, error) { if u == RootURI { return false, nil } @@ -69,7 +69,7 @@ func (r *spacerepo) CanRead(u fyne.URI) (bool, error) { return false, fmt.Errorf("%s: Not Yet Implemented", "SpaceRepository.CanRead") } -func (r *spacerepo) CanWrite(u fyne.URI) (bool, error) { +func (r *spaceRepository) CanWrite(u fyne.URI) (bool, error) { if u == RootURI { return false, nil } @@ -77,7 +77,7 @@ func (r *spacerepo) CanWrite(u fyne.URI) (bool, error) { return false, fmt.Errorf("%s: Not Yet Implemented", "SpaceRepository.CanWrite") } -func (r *spacerepo) Child(u fyne.URI, c string) (fyne.URI, error) { +func (r *spaceRepository) Child(u fyne.URI, c string) (fyne.URI, error) { if u == RootURI { return r.ParseURI(SPACE_SCHEME_PREFIX + c) } @@ -85,46 +85,46 @@ func (r *spacerepo) Child(u fyne.URI, c string) (fyne.URI, error) { return nil, fmt.Errorf("%s: Not Yet Implemented", "SpaceRepository.Child") } -func (r *spacerepo) Copy(src, dest fyne.URI) error { +func (r *spaceRepository) Copy(src, dest fyne.URI) error { // TODO return fmt.Errorf("%s: Not Yet Implemented", "SpaceRepository.Copy") } -func (r *spacerepo) CreateListable(u fyne.URI) error { +func (r *spaceRepository) CreateListable(u fyne.URI) error { // TODO return fmt.Errorf("%s: Not Yet Implemented", "SpaceRepository.CreateListable") } -func (r *spacerepo) Delete(u fyne.URI) error { +func (r *spaceRepository) Delete(u fyne.URI) error { // BC is indelible return repository.ErrOperationNotSupported } -func (r *spacerepo) Destroy(string) { +func (r *spaceRepository) Destroy(string) { // Do nothing } -func (r *spacerepo) Exists(u fyne.URI) (bool, error) { +func (r *spaceRepository) Exists(u fyne.URI) (bool, error) { // TODO return false, fmt.Errorf("%s: Not Yet Implemented", "SpaceRepository.Exists") } -func (r *spacerepo) List(u fyne.URI) ([]fyne.URI, error) { +func (r *spaceRepository) List(u fyne.URI) ([]fyne.URI, error) { // TODO return nil, fmt.Errorf("%s: Not Yet Implemented", "SpaceRepository.List") } -func (r *spacerepo) Move(fyne.URI, fyne.URI) error { +func (r *spaceRepository) Move(fyne.URI, fyne.URI) error { // BC is immutable return repository.ErrOperationNotSupported } -func (r *spacerepo) Parent(fyne.URI) (fyne.URI, error) { +func (r *spaceRepository) Parent(fyne.URI) (fyne.URI, error) { // TODO return nil, fmt.Errorf("%s: Not Yet Implemented", "SpaceRepository.Parent") } -func (r *spacerepo) ParseURI(s string) (fyne.URI, error) { +func (r *spaceRepository) ParseURI(s string) (fyne.URI, error) { if !strings.HasPrefix(s, SPACE_SCHEME_PREFIX) { return nil, storage.ErrInvalidURI } @@ -138,12 +138,24 @@ func (r *spacerepo) ParseURI(s string) (fyne.URI, error) { parts := strings.Split(s, "/") var fileHash []byte - if len(parts) > 1 { - h, err := base64.RawURLEncoding.DecodeString(parts[1]) - if err != nil { + h, err := base64.RawURLEncoding.DecodeString(parts[0]) + if err != nil { + return nil, err + } + fileHash = h + + if len(parts) == 1 { + var meta *spacego.Meta + if err := r.client.MetaForHash(r.node, fileHash, func(e *bcgo.BlockEntry, m *spacego.Meta) error { + meta = m + return nil + }); err != nil { return nil, err } - fileHash = h + if meta == nil { + return nil, fmt.Errorf("Could not load metadata for %s", s) + } + return NewFileURI(fileHash, meta), nil } var recordHash []byte @@ -155,22 +167,9 @@ func (r *spacerepo) ParseURI(s string) (fyne.URI, error) { recordHash = h } - switch parts[0] { + switch parts[1] { case "delta": return NewDeltaURI(fileHash, recordHash), nil - case "file": - node, err := r.client.GetNode() - if err != nil { - return nil, err - } - var meta *spacego.Meta - if err := r.client.GetMeta(node, fileHash, func(e *bcgo.BlockEntry, m *spacego.Meta) error { - meta = m - return nil - }); err != nil { - return nil, err - } - return NewFileURI(fileHash, meta), nil case "meta": return NewMetaURI(fileHash), nil case "preview": @@ -181,16 +180,16 @@ func (r *spacerepo) ParseURI(s string) (fyne.URI, error) { return nil, storage.ErrInvalidURI } -func (r *spacerepo) Reader(u fyne.URI) (fyne.URIReadCloser, error) { +func (r *spaceRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { // TODO return nil, fmt.Errorf("%s: Not Yet Implemented", "SpaceRepository.Reader") } -func (r *spacerepo) Register() { +func (r *spaceRepository) Register() { repository.Register(SPACE_SCHEME, r) } -func (r *spacerepo) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { +func (r *spaceRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { // TODO return nil, fmt.Errorf("%s: Not Yet Implemented", "SpaceRepository.Writer") } diff --git a/vendor/aletheiaware.com/spacefynego/storage/uri.go b/vendor/aletheiaware.com/spacefynego/storage/uri.go index ffc4369..c61247f 100644 --- a/vendor/aletheiaware.com/spacefynego/storage/uri.go +++ b/vendor/aletheiaware.com/spacefynego/storage/uri.go @@ -19,6 +19,7 @@ package storage import ( "aletheiaware.com/spacego" "encoding/base64" + "fmt" "fyne.io/fyne/v2" ) @@ -28,6 +29,7 @@ const ( ) type SpaceURI interface { + fmt.Stringer fyne.URI FileHash() []byte } diff --git a/vendor/aletheiaware.com/spacefynego/ui/data/icon.go b/vendor/aletheiaware.com/spacefynego/ui/data/icon.go index eddef23..515c10e 100644 --- a/vendor/aletheiaware.com/spacefynego/ui/data/icon.go +++ b/vendor/aletheiaware.com/spacefynego/ui/data/icon.go @@ -6,22 +6,27 @@ package data import "fyne.io/fyne/v2" var SpaceIcon = &fyne.StaticResource{ - StaticName: "space.svg", - StaticContent: []byte("\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n"), + StaticName: "space.svg", + StaticContent: []byte( + "\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n"), } var CameraPhotoIcon = &fyne.StaticResource{ - StaticName: "camera_photo.svg", - StaticContent: []byte("\n \n \n \n"), + StaticName: "camera_photo.svg", + StaticContent: []byte( + "\n \n \n \n"), } var CameraVideoIcon = &fyne.StaticResource{ - StaticName: "camera_video.svg", - StaticContent: []byte("\n \n \n"), + StaticName: "camera_video.svg", + StaticContent: []byte( + "\n \n \n"), } var MicrophoneIcon = &fyne.StaticResource{ - StaticName: "microphone.svg", - StaticContent: []byte("\n \n \n"), + StaticName: "microphone.svg", + StaticContent: []byte( + "\n \n \n"), } var StorageIcon = &fyne.StaticResource{ - StaticName: "storage.svg", - StaticContent: []byte("\n \n \n"), + StaticName: "storage.svg", + StaticContent: []byte( + "\n \n \n"), } diff --git a/vendor/aletheiaware.com/spacefynego/ui/data/logo.svg b/vendor/aletheiaware.com/spacefynego/ui/data/logo.svg new file mode 100644 index 0000000..96b92d6 --- /dev/null +++ b/vendor/aletheiaware.com/spacefynego/ui/data/logo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/vendor/aletheiaware.com/spacefynego/ui/metalist.go b/vendor/aletheiaware.com/spacefynego/ui/metalist.go index e1e6801..e083bc8 100644 --- a/vendor/aletheiaware.com/spacefynego/ui/metalist.go +++ b/vendor/aletheiaware.com/spacefynego/ui/metalist.go @@ -114,12 +114,15 @@ func (l *MetaList) Add(entry *bcgo.BlockEntry, meta *spacego.Meta) error { } func (l *MetaList) Clear() { + for k := range l.metas { + delete(l.metas, k) + } l.ids = nil l.Refresh() } -func (l *MetaList) Update(client *spaceclientgo.SpaceClient, node *bcgo.Node) error { - if err := client.List(node, l.Add); err != nil { +func (l *MetaList) Update(client spaceclientgo.SpaceClient, node bcgo.Node) error { + if err := client.AllMetas(node, l.Add); err != nil { return err } l.Refresh() diff --git a/vendor/aletheiaware.com/spacefynego/ui/registrarlist.go b/vendor/aletheiaware.com/spacefynego/ui/registrarlist.go index 3be8fb1..2bf62a0 100644 --- a/vendor/aletheiaware.com/spacefynego/ui/registrarlist.go +++ b/vendor/aletheiaware.com/spacefynego/ui/registrarlist.go @@ -133,14 +133,14 @@ func (l *RegistrarList) AddSubscription(entry *bcgo.BlockEntry, subscription *fi return nil } -func (l *RegistrarList) Update(client *spaceclientgo.SpaceClient, node *bcgo.Node) error { - if err := spacego.GetAllRegistrars(node, l.AddRegistrar); err != nil { +func (l *RegistrarList) Update(client spaceclientgo.SpaceClient, node bcgo.Node) error { + if err := spacego.AllRegistrars(node, l.AddRegistrar); err != nil { return err } - if err := spacego.GetAllRegistrationsForNode(node, l.AddRegistration); err != nil { + if err := spacego.AllRegistrationsForNode(node, l.AddRegistration); err != nil { return err } - if err := spacego.GetAllSubscriptionsForNode(node, l.AddSubscription); err != nil { + if err := spacego.AllSubscriptionsForNode(node, l.AddSubscription); err != nil { return err } sort.Slice(l.ids, func(i, j int) bool { diff --git a/vendor/aletheiaware.com/spacefynego/ui/viewer/image.go b/vendor/aletheiaware.com/spacefynego/ui/viewer/image.go new file mode 100644 index 0000000..fc8e57e --- /dev/null +++ b/vendor/aletheiaware.com/spacefynego/ui/viewer/image.go @@ -0,0 +1,107 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package viewer + +import ( + "aletheiaware.com/spacego" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" + "image" + _ "image/gif" + _ "image/jpeg" + _ "image/png" + "io" +) + +func init() { + generator := func() (Viewer, error) { + return NewImageViewer(), nil + } + Register(spacego.MIME_TYPE_IMAGE_GIF, generator) + Register(spacego.MIME_TYPE_IMAGE_JPEG, generator) + Register(spacego.MIME_TYPE_IMAGE_JPG, generator) + // TODO Register(spacego.MIME_TYPE_IMAGE_SVG, generator) + Register(spacego.MIME_TYPE_IMAGE_PNG, generator) +} + +type ImageViewer struct { + widget.BaseWidget + img image.Image +} + +func NewImageViewer() *ImageViewer { + v := &ImageViewer{} + v.ExtendBaseWidget(v) + return v +} + +func (v *ImageViewer) CreateRenderer() fyne.WidgetRenderer { + v.ExtendBaseWidget(v) + r := &imageViewerRenderer{ + viewer: v, + img: &canvas.Image{ + FillMode: canvas.ImageFillOriginal, + }, + } + r.scroller = container.NewScroll(r.img) + r.objects = []fyne.CanvasObject{r.scroller} + return r +} + +func (v *ImageViewer) MinSize() fyne.Size { + v.ExtendBaseWidget(v) + return v.BaseWidget.MinSize() +} + +func (v *ImageViewer) SetSource(source io.Reader) error { + i, _, err := image.Decode(source) + if err != nil { + return err + } + v.img = i + v.Refresh() + return nil +} + +type imageViewerRenderer struct { + viewer *ImageViewer + img *canvas.Image + scroller *container.Scroll + objects []fyne.CanvasObject +} + +func (r *imageViewerRenderer) Destroy() {} + +func (r *imageViewerRenderer) Layout(size fyne.Size) { + r.scroller.Resize(size) +} + +func (r *imageViewerRenderer) MinSize() fyne.Size { + return r.scroller.MinSize() +} + +func (r *imageViewerRenderer) Objects() []fyne.CanvasObject { + return r.objects +} + +func (r *imageViewerRenderer) Refresh() { + r.img.Image = r.viewer.img + r.img.Refresh() + r.scroller.Refresh() +} diff --git a/vendor/aletheiaware.com/spacefynego/ui/viewer/text.go b/vendor/aletheiaware.com/spacefynego/ui/viewer/text.go new file mode 100644 index 0000000..0b7503e --- /dev/null +++ b/vendor/aletheiaware.com/spacefynego/ui/viewer/text.go @@ -0,0 +1,98 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package viewer + +import ( + "aletheiaware.com/spacego" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" + "io" + "io/ioutil" +) + +func init() { + Register(spacego.MIME_TYPE_TEXT_PLAIN, func() (Viewer, error) { + return NewTextPlainViewer(), nil + }) +} + +type TextPlainViewer struct { + widget.BaseWidget + text string +} + +func NewTextPlainViewer() *TextPlainViewer { + v := &TextPlainViewer{} + v.ExtendBaseWidget(v) + return v +} + +func (v *TextPlainViewer) CreateRenderer() fyne.WidgetRenderer { + v.ExtendBaseWidget(v) + r := &textPlainViewerRenderer{ + viewer: v, + label: &widget.Label{ + Wrapping: fyne.TextWrapWord, + }, + } + r.scroller = container.NewVScroll(r.label) + r.objects = []fyne.CanvasObject{r.scroller} + return r +} + +func (v *TextPlainViewer) MinSize() fyne.Size { + v.ExtendBaseWidget(v) + return v.BaseWidget.MinSize() +} + +func (v *TextPlainViewer) SetSource(source io.Reader) error { + bytes, err := ioutil.ReadAll(source) + if err != nil { + return err + } + v.text = string(bytes) + v.Refresh() + return nil +} + +type textPlainViewerRenderer struct { + viewer *TextPlainViewer + label *widget.Label + scroller *container.Scroll + objects []fyne.CanvasObject +} + +func (r *textPlainViewerRenderer) Destroy() {} + +func (r *textPlainViewerRenderer) Layout(size fyne.Size) { + r.scroller.Resize(size) +} + +func (r *textPlainViewerRenderer) MinSize() fyne.Size { + return r.scroller.MinSize() +} + +func (r *textPlainViewerRenderer) Objects() []fyne.CanvasObject { + return r.objects +} + +func (r *textPlainViewerRenderer) Refresh() { + r.label.Text = r.viewer.text + r.label.Refresh() + r.scroller.Refresh() +} diff --git a/vendor/aletheiaware.com/spacefynego/ui/viewer/viewer.go b/vendor/aletheiaware.com/spacefynego/ui/viewer/viewer.go index fa4db6c..c5f6370 100644 --- a/vendor/aletheiaware.com/spacefynego/ui/viewer/viewer.go +++ b/vendor/aletheiaware.com/spacefynego/ui/viewer/viewer.go @@ -1,5 +1,5 @@ /* - * Copyright 2020 Aletheia Ware LLC + * Copyright 2020-2021 Aletheia Ware LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,75 +17,34 @@ package viewer import ( - "aletheiaware.com/spacego" + "fmt" "fyne.io/fyne/v2" - "fyne.io/fyne/v2/canvas" - "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/widget" - "image" - _ "image/gif" - _ "image/jpeg" - _ "image/png" "io" - "io/ioutil" - "log" + "strings" ) -func GetViewer(meta *spacego.Meta, source io.Reader) fyne.CanvasObject { - switch meta.GetType() { - case spacego.MIME_TYPE_TEXT_PLAIN: - return NewTextPlain(source) - case spacego.MIME_TYPE_IMAGE_GIF: - fallthrough - case spacego.MIME_TYPE_IMAGE_JPEG: - fallthrough - // TODO case spacego.MIME_TYPE_IMAGE_SVG: - // TODO fallthrough - case spacego.MIME_TYPE_IMAGE_PNG: - return NewImage(source) - } - return nil -} - -func NewTextPlain(source io.Reader) fyne.CanvasObject { - // Create label to hold text - label := &widget.Label{ - Wrapping: fyne.TextWrapWord, - } - scroller := container.NewVScroll(label) +// generatorTable stores the mapping of mime types to generators of Viewers. +var generatorTable map[string]func() (Viewer, error) = map[string]func() (Viewer, error){} - // Create goroutine to load file contents and update label - go func() { - bytes, err := ioutil.ReadAll(source) - if err != nil { - log.Println("Error:", err) - return - } - label.SetText(string(bytes)) - scroller.Refresh() - }() +// Viewer represents a fyne.CanvasObject that can view a file. +type Viewer interface { + fyne.CanvasObject + SetSource(io.Reader) error +} - return scroller +// Register registers a function that can generate a generator. +func Register(mime string, generator func() (Viewer, error)) { + generatorTable[strings.ToLower(mime)] = generator } -func NewImage(source io.Reader) fyne.CanvasObject { - // Create image to hold image - img := &canvas.Image{ - FillMode: canvas.ImageFillOriginal, - } - scroller := container.NewScroll(img) +// ForMime returns the Viewer instance which is registered to handle URIs +// of the given mime. +func ForMime(mime string) (Viewer, error) { + generator, ok := generatorTable[strings.ToLower(mime)] - // Create goroutine to load file contents and update image - go func() { - i, _, err := image.Decode(source) - if err != nil { - log.Println("Error:", err) - return - } - img.Image = i - img.Refresh() - scroller.Refresh() - }() + if !ok { + return nil, fmt.Errorf("no generator registered for mime '%s'", mime) + } - return scroller + return generator() } diff --git a/vendor/aletheiaware.com/spacego/closer.go b/vendor/aletheiaware.com/spacego/closer.go new file mode 100644 index 0000000..98fbdb4 --- /dev/null +++ b/vendor/aletheiaware.com/spacego/closer.go @@ -0,0 +1,42 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package spacego + +import "io" + +type Closer struct { + writer io.Writer + closer func() error +} + +func NewCloser(writer io.Writer, closer func() error) io.WriteCloser { + return &Closer{ + writer: writer, + closer: closer, + } +} + +func (c *Closer) Write(p []byte) (n int, err error) { + return c.writer.Write(p) +} + +func (c *Closer) Close() error { + if f := c.closer; f != nil { + return f() + } + return nil +} diff --git a/vendor/aletheiaware.com/spacego/diff.go b/vendor/aletheiaware.com/spacego/diff.go new file mode 100644 index 0000000..0d00043 --- /dev/null +++ b/vendor/aletheiaware.com/spacego/diff.go @@ -0,0 +1,206 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package spacego + +/* + Eugene W. Myers - An O(ND)Difference Algorithm and Its Variations + + a + 0 1 2 3 4 5 + 0*-*-*-*-*-* + |\|\|\|\|\| + 1*-*-*-*-*-* + |\|\|\|\|\| + b 2*-*-*-*-*-* + |\|\|\|\|\| + 3*-*-*-*-*-* + |\|\|\|\|\| + 4*-*-*-*-*-* + |\|\|\|\|\| + 5*-*-*-*-*-* + + * x, y point + - delete + | insert + \ match +*/ + +// Compact combines deltas with same offset or consecutive deletes. +func Compact(deltas []*Delta) (results []*Delta) { + for i := 0; i < len(deltas); { + first := deltas[i] + j := i + 1 + for j < len(deltas) { + next := deltas[j] + if first.Offset != next.Offset && first.Offset+first.Delete != next.Offset { + break + } + first.Delete += next.Delete + first.Insert = append(first.Insert, next.Insert...) + j++ + } + i = j + results = append(results, first) + } + return +} + +// Difference returns a sequence of deltas that transform the first of the given byte arrays into the second. +func Difference(a, b []byte) []*Delta { + n := len(a) + m := len(b) + edits := edits(a, b, n, m) + if edits < 0 { + // Error determining length of edit script + return nil + } + ds := deltas(a, b, n, m, edits) + // Compact deltas + ds = Compact(ds) + // Rebase deltas into sequence + var change uint64 + for _, d := range ds { + d.Offset += change + change -= d.Delete + change += uint64(len(d.Insert)) + } + return ds +} + +func edits(a, b []byte, n, m int) int { + for _, max := range []int{ + minimum(n, m), + maximum(n, m), + n + m, + n * m, + } { + v := make(map[int]int, max+2) + v[1] = 0 + for d := 0; d <= max; d++ { + start := -(d - 2*maximum(0, d-m)) + end := d - 2*maximum(0, d-n) + for k := start; k <= end; k = k + 2 { + x, y := next(a, b, n, m, v, d, k) + v[k] = x + if x >= n && y >= m { + return d + } + } + } + } + return -1 +} + +func deltas(a, b []byte, n, m int, max int) []*Delta { + v := make(map[int]int, max+2) + v[1] = 0 + vs := make([]map[int]int, max+1) + for d := 0; d <= max; d++ { + start := -(d - 2*maximum(0, d-m)) + end := d - 2*maximum(0, d-n) + count := (end-start)/2 + 1 + vs[d] = make(map[int]int, count) + for k := start; k <= end; k = k + 2 { + x, y := next(a, b, n, m, v, d, k) + v[k] = x + vs[d][k] = x + if x >= n && y >= m { + return backtrack(a, b, vs, d, n-m) + } + } + } + return nil +} + +func backtrack(a, b []byte, vs []map[int]int, d, k int) []*Delta { + if d <= 0 { + return nil + } + prev := vs[d-1] + delta := &Delta{} + delete, dok := prev[k-1] + insert, iok := prev[k+1] + if dok && iok { + // Select the best + if delete >= insert { + iok = false + } else { + dok = false + } + } + switch { + case dok: + k = k - 1 + delta.Offset = uint64(delete) + delta.Delete = 1 + case iok: + k = k + 1 + delta.Offset = uint64(insert) + delta.Insert = []byte{b[insert-k]} + default: + // Uh oh + return nil + } + return append(backtrack(a, b, vs, d-1, k), delta) +} + +func next(a, b []byte, n, m int, v map[int]int, d, k int) (x int, y int) { + switch { + case k == -d: + // Left border so choose k above + x = v[k+1] + case k == d: + // Top border so choose k below + x = v[k-1] + 1 + default: + above, aok := v[k+1] + below, bok := v[k-1] + if aok && bok { + // Choose best + if below < above { + x = above + } else { + x = below + 1 + } + } else if aok { + // Choose above + x = above + } else { + // Choose below + x = below + 1 + } + } + y = x - k + for x < n && y < m && a[x] == b[y] { + x, y = x+1, y+1 + } + return +} + +func minimum(a, b int) int { + if a < b { + return a + } + return b +} + +func maximum(a, b int) int { + if a > b { + return a + } + return b +} diff --git a/vendor/aletheiaware.com/spacego/filter.go b/vendor/aletheiaware.com/spacego/filter.go new file mode 100644 index 0000000..5a3645f --- /dev/null +++ b/vendor/aletheiaware.com/spacego/filter.go @@ -0,0 +1,82 @@ +/* + * Copyright 2021 Aletheia Ware LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package spacego + +type MetaFilter interface { + Filter(*Meta) bool +} + +func NewNameFilter(names ...string) MetaFilter { + return &nameFilter{ + names: names, + } +} + +type nameFilter struct { + names []string +} + +func (f *nameFilter) Filter(meta *Meta) bool { + for _, value := range f.names { + if meta.Name == value { + return true + } + } + return false +} + +func NewTypeFilter(types ...string) MetaFilter { + return &typeFilter{ + types: types, + } +} + +type typeFilter struct { + types []string +} + +func (f *typeFilter) Filter(meta *Meta) bool { + for _, value := range f.types { + if meta.Type == value { + return true + } + } + return false +} + +type TagFilter interface { + Filter(*Tag) bool +} + +func NewTagFilter(tags ...string) TagFilter { + return &tagFilter{ + tags: tags, + } +} + +type tagFilter struct { + tags []string +} + +func (f *tagFilter) Filter(tag *Tag) bool { + for _, value := range f.tags { + if tag.Value == value { + return true + } + } + return false +} diff --git a/vendor/aletheiaware.com/spacego/go.mod b/vendor/aletheiaware.com/spacego/go.mod index f726a01..789356b 100644 --- a/vendor/aletheiaware.com/spacego/go.mod +++ b/vendor/aletheiaware.com/spacego/go.mod @@ -3,9 +3,10 @@ module aletheiaware.com/spacego go 1.15 require ( - aletheiaware.com/bcgo v1.1.4 - aletheiaware.com/financego v1.1.3 - aletheiaware.com/testinggo v1.1.2 - github.com/golang/protobuf v1.4.3 + aletheiaware.com/bcgo v1.2.3 + aletheiaware.com/cryptogo v1.2.2 + aletheiaware.com/financego v1.2.3 + aletheiaware.com/testinggo v1.2.2 + github.com/golang/protobuf v1.5.2 github.com/stretchr/testify v1.7.0 ) diff --git a/vendor/aletheiaware.com/spacego/go.sum b/vendor/aletheiaware.com/spacego/go.sum index e91df70..d512e58 100644 --- a/vendor/aletheiaware.com/spacego/go.sum +++ b/vendor/aletheiaware.com/spacego/go.sum @@ -1,26 +1,20 @@ -aletheiaware.com/aliasgo v1.1.3 h1:RnJhpWcbH7KWWWgIvUCVS+++mzpjYNk/dQm4o1G0lX8= -aletheiaware.com/aliasgo v1.1.3/go.mod h1:JY9/j4q6ZniHb0vKO7CJJ3M03eTVhczoIIhJBZ6Sa3w= -aletheiaware.com/bcgo v1.1.4 h1:HuAk12UeOvtIXlc7WN2XIj9tV+jNA5uCi+D8Z0V2twU= -aletheiaware.com/bcgo v1.1.4/go.mod h1:GXvFFZ8JrATGrvuKA0J3ucf9+91eC94ggphNVpg3XUM= -aletheiaware.com/cryptogo v1.1.1 h1:XrzGXcTgYQbuL3tQv/idVzAIblb2k+o77iigiQiXTUQ= -aletheiaware.com/cryptogo v1.1.1/go.mod h1:sT8jDe5zWSIswZDAilLwfX2N6l4WOFQBm+4lYxx1Ae0= -aletheiaware.com/financego v1.1.3 h1:np43b+Vi2jK+PcjuZm97PJmtzIckhLVAHNFU5DzsKwI= -aletheiaware.com/financego v1.1.3/go.mod h1:Ht3zPGQyenlkxLXMQcKww6ctjt2bZcyLDdLz+/Koml0= -aletheiaware.com/testinggo v1.1.2 h1:/zCBvslySEY4uJ2qnnyvhFdgIERa/jzlgHBOmS4lL1k= -aletheiaware.com/testinggo v1.1.2/go.mod h1:bqmrqRyMkGbTa9E/1D8xHE0KLmOw+HRG0skc/XwrdcY= +aletheiaware.com/aliasgo v1.2.3 h1:joMErbHdyo+jVbIoA9HWMPmUVfhZjabBVaB5AnYYObQ= +aletheiaware.com/aliasgo v1.2.3/go.mod h1:wSp0m2ZOXA3M3ZKFcUtcf2ANBio5JSXxQx07IpxwaGM= +aletheiaware.com/bcgo v1.2.3 h1:5vRjjrkmlSh0/cwhY5u+0S4RUpvTCAMN1HVJMBl9A88= +aletheiaware.com/bcgo v1.2.3/go.mod h1:zNPBDrox6aUVv8ns5UOzcaDXzD/p5tZ0lGSxlfT6/Rs= +aletheiaware.com/cryptogo v1.2.2 h1:d7vEEgf3bZFnLk+HG1wCAY/pgRz+zNYvKFpxsli3Mng= +aletheiaware.com/cryptogo v1.2.2/go.mod h1:B1mJVIsfEDJoovkD2fLsZXgXxR1AAe2cDmjFwt7Eau4= +aletheiaware.com/financego v1.2.3 h1:0pDUPPSEcRbzKGR9HTvcrMQ7/anUs4EByub+yB/Unvo= +aletheiaware.com/financego v1.2.3/go.mod h1:wSeFDTfW+2OaOt5AEo8OGAfXpaQrU7+VraFxR1X5i4Q= +aletheiaware.com/testinggo v1.2.2 h1:w+ir8ehcnIcZ+jTjalGWAkh3So9PaJm5g3CPgLnPtXE= +aletheiaware.com/testinggo v1.2.2/go.mod h1:TijVTRIGnue9UHlxT9YgLp5VGWOo4PI9VRflCm4v4xo= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -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.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -28,27 +22,22 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stripe/stripe-go v70.15.0+incompatible h1:hNML7M1zx8RgtepEMlxyu/FpVPrP7KZm1gPFQquJQvM= github.com/stripe/stripe-go v70.15.0+incompatible/go.mod h1:A1dQZmO/QypXmsL0T8axYZkSN/uA/T/A64pfKdBAMiY= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc h1:+q90ECDSAQirdykUN6sPEiBXBsp8Csjcca8Oy7bgLTA= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= diff --git a/vendor/aletheiaware.com/spacego/space.go b/vendor/aletheiaware.com/spacego/space.go index ef61454..9c36fa5 100644 --- a/vendor/aletheiaware.com/spacego/space.go +++ b/vendor/aletheiaware.com/spacego/space.go @@ -18,17 +18,18 @@ package spacego import ( "aletheiaware.com/bcgo" + "aletheiaware.com/bcgo/channel" + "aletheiaware.com/bcgo/validation" "aletheiaware.com/financego" - "crypto/rsa" "github.com/golang/protobuf/proto" "io" + "log" + "sort" + "strings" ) const ( SPACE = "S P A C E" - SPACE_HOUR = "Space-Hour" - SPACE_DAY = "Space-Day" - SPACE_YEAR = "Space-Year" SPACE_CHARGE = "Space-Charge" SPACE_INVOICE = "Space-Invoice" SPACE_REGISTRAR = "Space-Registrar" @@ -36,13 +37,18 @@ const ( SPACE_SUBSCRIPTION = "Space-Subscription" SPACE_USAGE_RECORD = "Space-Usage-Record" - SPACE_PREFIX = "Space-" - SPACE_PREFIX_DELTA = "Space-Delta-" - SPACE_PREFIX_META = "Space-Meta-" - SPACE_PREFIX_PREVIEW = "Space-Preview-" - SPACE_PREFIX_TAG = "Space-Tag-" + SPACE_PREFIX = "Space-" + SPACE_PREFIX_DELTA = "Space-Delta-" + SPACE_PREFIX_META = "Space-Meta-" + SPACE_PREFIX_PREVIEW = "Space-Preview-" + SPACE_PREFIX_TAG = "Space-Tag-" + SPACE_PREFIX_VALIDATION = "Space-Validation-" - THRESHOLD = bcgo.THRESHOLD_G + THRESHOLD_ACCOUNTING = bcgo.THRESHOLD_G // Charge, Invoice, Registrar, Registration, Subscription, Usage Record Channels + THRESHOLD_CUSTOMER = bcgo.THRESHOLD_Z // Delta, Meta, Preview, Tag Channels + THRESHOLD_VALIDATION = validation.THRESHOLD_PERIOD_DAY + + PERIOD_VALIDATION = validation.PERIOD_DAILY MIME_TYPE_UNKNOWN = "?/?" MIME_TYPE_IMAGE_JPEG = "image/jpeg" @@ -76,7 +82,7 @@ type RegistrarCallback func(*bcgo.BlockEntry, *Registrar) error type TagCallback func(*bcgo.BlockEntry, *Tag) error -func GetSpaceHosts() []string { +func SpaceHosts() []string { if bcgo.IsLive() { return []string{ "space-nyc.aletheiaware.com", @@ -88,78 +94,110 @@ func GetSpaceHosts() []string { } } -func openLivePoWChannel(name string, threshold uint64) *bcgo.Channel { - c := bcgo.OpenPoWChannel(name, threshold) - c.AddValidator(&bcgo.LiveValidator{}) - return c +func MimeTypes() []string { + mimes := []string{ + MIME_TYPE_IMAGE_JPEG, + MIME_TYPE_IMAGE_JPG, + MIME_TYPE_IMAGE_GIF, + MIME_TYPE_IMAGE_PNG, + MIME_TYPE_IMAGE_WEBP, + MIME_TYPE_TEXT_PLAIN, + MIME_TYPE_PDF, + MIME_TYPE_PROTOBUF, + MIME_TYPE_VIDEO_MPEG, + MIME_TYPE_AUDIO_MPEG, + } + sort.Strings(mimes) + return mimes } -func OpenHourChannel() *bcgo.Channel { - return openLivePoWChannel(SPACE_HOUR, bcgo.THRESHOLD_PERIOD_HOUR) +func Validator(node bcgo.Node, channel bcgo.Channel, listener bcgo.MiningListener) validation.Periodic { + return validation.NewDaily(node, channel, listener) } -func OpenDayChannel() *bcgo.Channel { - return openLivePoWChannel(SPACE_DAY, bcgo.THRESHOLD_PERIOD_DAY) +func openChannel(name string, threshold uint64) bcgo.Channel { + c := channel.NewPoW(name, threshold) + c.AddValidator(&validation.Live{}) + // TODO c.AddValidator(&validation.Signature{}) + return c } -func OpenYearChannel() *bcgo.Channel { - return openLivePoWChannel(SPACE_YEAR, bcgo.THRESHOLD_PERIOD_YEAR) +/* TODO +func openCustomerChannel(customer, name string, threshold uint64) bcgo.Channel { + c := openChannel(name, threshold) + c.AddValidator(&validation.Creator{ + Creator: customer, + }) + return c } +*/ -func OpenChargeChannel() *bcgo.Channel { - return openLivePoWChannel(SPACE_CHARGE, THRESHOLD) +func OpenChargeChannel() bcgo.Channel { + return openChannel(SPACE_CHARGE, THRESHOLD_ACCOUNTING) } -func OpenInvoiceChannel() *bcgo.Channel { - return openLivePoWChannel(SPACE_INVOICE, THRESHOLD) +func OpenInvoiceChannel() bcgo.Channel { + return openChannel(SPACE_INVOICE, THRESHOLD_ACCOUNTING) } -func OpenRegistrarChannel() *bcgo.Channel { - return openLivePoWChannel(SPACE_REGISTRAR, THRESHOLD) +func OpenRegistrarChannel() bcgo.Channel { + return openChannel(SPACE_REGISTRAR, THRESHOLD_ACCOUNTING) } -func OpenRegistrationChannel() *bcgo.Channel { - return openLivePoWChannel(SPACE_REGISTRATION, THRESHOLD) +func OpenRegistrationChannel() bcgo.Channel { + return openChannel(SPACE_REGISTRATION, THRESHOLD_ACCOUNTING) } -func OpenSubscriptionChannel() *bcgo.Channel { - return openLivePoWChannel(SPACE_SUBSCRIPTION, THRESHOLD) +func OpenSubscriptionChannel() bcgo.Channel { + return openChannel(SPACE_SUBSCRIPTION, THRESHOLD_ACCOUNTING) } -func OpenUsageRecordChannel() *bcgo.Channel { - return openLivePoWChannel(SPACE_USAGE_RECORD, THRESHOLD) +func OpenUsageRecordChannel() bcgo.Channel { + return openChannel(SPACE_USAGE_RECORD, THRESHOLD_ACCOUNTING) } -func GetDeltaChannelName(metaId string) string { +func DeltaChannelName(metaId string) string { return SPACE_PREFIX_DELTA + metaId } -func GetMetaChannelName(alias string) string { +func MetaChannelName(alias string) string { return SPACE_PREFIX_META + alias } -func GetPreviewChannelName(metaId string) string { +func PreviewChannelName(metaId string) string { return SPACE_PREFIX_PREVIEW + metaId } -func GetTagChannelName(metaId string) string { +func TagChannelName(metaId string) string { return SPACE_PREFIX_TAG + metaId } -func OpenDeltaChannel(metaId string) *bcgo.Channel { - return openLivePoWChannel(GetDeltaChannelName(metaId), THRESHOLD) +func ValidationChannelName(alias string) string { + return SPACE_PREFIX_VALIDATION + alias +} + +func OpenDeltaChannel(metaId string) bcgo.Channel { + // TODO return openCustomerChannel(alias, DeltaChannelName(metaId), THRESHOLD_CUSTOMER) + return openChannel(DeltaChannelName(metaId), THRESHOLD_CUSTOMER) +} + +func OpenMetaChannel(alias string) bcgo.Channel { + // TODO return openCustomerChannel(alias, MetaChannelName(alias), THRESHOLD_CUSTOMER) + return openChannel(MetaChannelName(alias), THRESHOLD_CUSTOMER) } -func OpenMetaChannel(alias string) *bcgo.Channel { - return openLivePoWChannel(GetMetaChannelName(alias), THRESHOLD) +func OpenPreviewChannel(metaId string) bcgo.Channel { + // TODO return openCustomerChannel(alias, PreviewChannelName(metaId), THRESHOLD_CUSTOMER) + return openChannel(PreviewChannelName(metaId), THRESHOLD_CUSTOMER) } -func OpenPreviewChannel(metaId string) *bcgo.Channel { - return openLivePoWChannel(GetPreviewChannelName(metaId), THRESHOLD) +func OpenTagChannel(metaId string) bcgo.Channel { + // TODO return openCustomerChannel(alias, TagChannelName(metaId), THRESHOLD_CUSTOMER) + return openChannel(TagChannelName(metaId), THRESHOLD_CUSTOMER) } -func OpenTagChannel(metaId string) *bcgo.Channel { - return openLivePoWChannel(GetTagChannelName(metaId), THRESHOLD) +func OpenValidationChannel(alias string) bcgo.Channel { + return openChannel(ValidationChannelName(alias), THRESHOLD_VALIDATION) } func ApplyDelta(delta *Delta, input []byte) []byte { @@ -204,22 +242,33 @@ func CreateDeltas(reader io.Reader, max uint64, callback func(*Delta) error) err return nil } -func GetThreshold(channel string) uint64 { +func Threshold(channel string) uint64 { switch channel { - case SPACE_HOUR: - return bcgo.THRESHOLD_PERIOD_HOUR - case SPACE_DAY: - return bcgo.THRESHOLD_PERIOD_DAY - case SPACE_YEAR: - return bcgo.THRESHOLD_PERIOD_YEAR + case SPACE_CHARGE, + SPACE_INVOICE, + SPACE_REGISTRAR, + SPACE_REGISTRATION, + SPACE_SUBSCRIPTION, + SPACE_USAGE_RECORD: + return THRESHOLD_ACCOUNTING default: - return THRESHOLD + switch { + case strings.HasPrefix(channel, SPACE_PREFIX_VALIDATION): + return THRESHOLD_VALIDATION + case strings.HasPrefix(channel, SPACE_PREFIX_DELTA), + strings.HasPrefix(channel, SPACE_PREFIX_META), + strings.HasPrefix(channel, SPACE_PREFIX_PREVIEW), + strings.HasPrefix(channel, SPACE_PREFIX_TAG): + return THRESHOLD_CUSTOMER + default: + return 0 + } } } -func GetRegistrar(registrars *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alias string) (*Registrar, error) { +func RegistrarForAlias(registrars bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alias string) (*Registrar, error) { var registrar *Registrar - if err := bcgo.Read(registrars.Name, registrars.Head, nil, cache, network, "", nil, nil, func(entry *bcgo.BlockEntry, key, data []byte) error { + if err := bcgo.Read(registrars.Name(), registrars.Head(), nil, cache, network, nil, nil, func(entry *bcgo.BlockEntry, key, data []byte) error { // Unmarshal as Registrar r := &Registrar{} err := proto.Unmarshal(data, r) @@ -228,12 +277,12 @@ func GetRegistrar(registrars *bcgo.Channel, cache bcgo.Cache, network bcgo.Netwo } if r.Merchant.Alias == alias { registrar = r - return bcgo.StopIterationError{} + return bcgo.ErrStopIteration{} } return nil }); err != nil { switch err.(type) { - case bcgo.StopIterationError: + case bcgo.ErrStopIteration: // Do nothing break default: @@ -243,29 +292,15 @@ func GetRegistrar(registrars *bcgo.Channel, cache bcgo.Cache, network bcgo.Netwo return registrar, nil } -func GetRegistrars(registrars *bcgo.Channel, cache bcgo.Cache, network bcgo.Network) (rs []*Registrar) { - bcgo.Read(registrars.Name, registrars.Head, nil, cache, network, "", nil, nil, func(entry *bcgo.BlockEntry, key, data []byte) error { - // Unmarshal as Registrar - r := &Registrar{} - err := proto.Unmarshal(data, r) - if err != nil { - return err - } - rs = append(rs, r) - return nil - }) - return -} - -// GetAllRegistrars triggers the given callback for each registrar. -func GetAllRegistrars(node *bcgo.Node, callback RegistrarCallback) error { - registrars := node.GetOrOpenChannel(SPACE_REGISTRAR, func() *bcgo.Channel { +// AllRegistrars triggers the given callback for each registrar. +func AllRegistrars(node bcgo.Node, callback RegistrarCallback) error { + registrars := node.OpenChannel(SPACE_REGISTRAR, func() bcgo.Channel { return OpenRegistrarChannel() }) - if err := registrars.Refresh(node.Cache, node.Network); err != nil { - // Ignored + if err := registrars.Refresh(node.Cache(), node.Network()); err != nil { + log.Println(err) } - return bcgo.Read(registrars.Name, registrars.Head, nil, node.Cache, node.Network, "", nil, nil, func(entry *bcgo.BlockEntry, key, data []byte) error { + return bcgo.Read(registrars.Name(), registrars.Head(), nil, node.Cache(), node.Network(), node.Account(), nil, func(entry *bcgo.BlockEntry, key, data []byte) error { // Unmarshal as Registrar r := &Registrar{} err := proto.Unmarshal(data, r) @@ -276,11 +311,11 @@ func GetAllRegistrars(node *bcgo.Node, callback RegistrarCallback) error { }) } -// GetAllRegistrarsForNode triggers the given callback for each registrar with which the given node is registered, and optionally subscribed -func GetAllRegistrarsForNode(node *bcgo.Node, callback func(*Registrar, *financego.Registration, *financego.Subscription) error) error { +// AllRegistrarsForNode triggers the given callback for each registrar with which the given node is registered, and optionally subscribed +func AllRegistrarsForNode(node bcgo.Node, callback func(*Registrar, *financego.Registration, *financego.Subscription) error) error { // Get registrars as := make(map[string]*Registrar) - if err := GetAllRegistrars(node, func(e *bcgo.BlockEntry, r *Registrar) error { + if err := AllRegistrars(node, func(e *bcgo.BlockEntry, r *Registrar) error { as[r.Merchant.Alias] = r return nil }); err != nil { @@ -288,7 +323,7 @@ func GetAllRegistrarsForNode(node *bcgo.Node, callback func(*Registrar, *finance } // Get registrations rs := make(map[string]*financego.Registration) - if err := GetAllRegistrationsForNode(node, func(e *bcgo.BlockEntry, r *financego.Registration) error { + if err := AllRegistrationsForNode(node, func(e *bcgo.BlockEntry, r *financego.Registration) error { if _, ok := as[r.MerchantAlias]; ok { rs[r.MerchantAlias] = r } @@ -298,7 +333,7 @@ func GetAllRegistrarsForNode(node *bcgo.Node, callback func(*Registrar, *finance } // Get subscriptions ss := make(map[string]*financego.Subscription) - if err := GetAllSubscriptionsForNode(node, func(e *bcgo.BlockEntry, s *financego.Subscription) error { + if err := AllSubscriptionsForNode(node, func(e *bcgo.BlockEntry, s *financego.Subscription) error { if _, ok := as[s.MerchantAlias]; ok { ss[s.MerchantAlias] = s } @@ -318,52 +353,54 @@ func GetAllRegistrarsForNode(node *bcgo.Node, callback func(*Registrar, *finance return nil } -// GetAllRegistrationsForNode triggers the given callback for each registration. -func GetAllRegistrationsForNode(node *bcgo.Node, callback financego.RegistrationCallback) error { - registrations := node.GetOrOpenChannel(SPACE_REGISTRATION, func() *bcgo.Channel { +// AllRegistrationsForNode triggers the given callback for each registration. +func AllRegistrationsForNode(node bcgo.Node, callback financego.RegistrationCallback) error { + registrations := node.OpenChannel(SPACE_REGISTRATION, func() bcgo.Channel { return OpenRegistrationChannel() }) - if err := registrations.Refresh(node.Cache, node.Network); err != nil { - // Ignored + if err := registrations.Refresh(node.Cache(), node.Network()); err != nil { + log.Println(err) } - return bcgo.Read(registrations.Name, registrations.Head, nil, node.Cache, node.Network, node.Alias, node.Key, nil, func(entry *bcgo.BlockEntry, key, data []byte) error { + alias := node.Account().Alias() + return bcgo.Read(registrations.Name(), registrations.Head(), nil, node.Cache(), node.Network(), node.Account(), nil, func(entry *bcgo.BlockEntry, key, data []byte) error { // Unmarshal as Registration r := &financego.Registration{} err := proto.Unmarshal(data, r) if err != nil { return err } - if node.Alias == r.CustomerAlias { + if alias == r.CustomerAlias { return callback(entry, r) } return nil }) } -// GetAllSubscriptionsForNode triggers the given callback for each subscription. -func GetAllSubscriptionsForNode(node *bcgo.Node, callback financego.SubscriptionCallback) error { - subscriptions := node.GetOrOpenChannel(SPACE_SUBSCRIPTION, func() *bcgo.Channel { +// AllSubscriptionsForNode triggers the given callback for each subscription. +func AllSubscriptionsForNode(node bcgo.Node, callback financego.SubscriptionCallback) error { + subscriptions := node.OpenChannel(SPACE_SUBSCRIPTION, func() bcgo.Channel { return OpenSubscriptionChannel() }) - if err := subscriptions.Refresh(node.Cache, node.Network); err != nil { - // Ignored + if err := subscriptions.Refresh(node.Cache(), node.Network()); err != nil { + log.Println(err) } - return bcgo.Read(subscriptions.Name, subscriptions.Head, nil, node.Cache, node.Network, node.Alias, node.Key, nil, func(entry *bcgo.BlockEntry, key, data []byte) error { + alias := node.Account().Alias() + return bcgo.Read(subscriptions.Name(), subscriptions.Head(), nil, node.Cache(), node.Network(), node.Account(), nil, func(entry *bcgo.BlockEntry, key, data []byte) error { // Unmarshal as Subscription s := &financego.Subscription{} err := proto.Unmarshal(data, s) if err != nil { return err } - if node.Alias == s.CustomerAlias { + if alias == s.CustomerAlias { return callback(entry, s) } return nil }) } -func GetDelta(deltas *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alias string, key *rsa.PrivateKey, recordHash []byte, callback DeltaCallback) error { - return bcgo.Read(deltas.Name, deltas.Head, nil, cache, network, alias, key, recordHash, func(entry *bcgo.BlockEntry, key, data []byte) error { +func ReadDelta(deltas bcgo.Channel, cache bcgo.Cache, network bcgo.Network, account bcgo.Account, recordHash []byte, callback DeltaCallback) error { + return bcgo.Read(deltas.Name(), deltas.Head(), nil, cache, network, account, recordHash, func(entry *bcgo.BlockEntry, key, data []byte) error { // Unmarshal as Delta d := &Delta{} err := proto.Unmarshal(data, d) @@ -374,8 +411,8 @@ func GetDelta(deltas *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alia }) } -func GetMeta(metas *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alias string, key *rsa.PrivateKey, recordHash []byte, callback MetaCallback) error { - return bcgo.Read(metas.Name, metas.Head, nil, cache, network, alias, key, recordHash, func(entry *bcgo.BlockEntry, key, data []byte) error { +func ReadMeta(metas bcgo.Channel, cache bcgo.Cache, network bcgo.Network, account bcgo.Account, recordHash []byte, callback MetaCallback) error { + return bcgo.Read(metas.Name(), metas.Head(), nil, cache, network, account, recordHash, func(entry *bcgo.BlockEntry, key, data []byte) error { // Unmarshal as Meta meta := &Meta{} if err := proto.Unmarshal(data, meta); err != nil { @@ -385,8 +422,8 @@ func GetMeta(metas *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alias }) } -func GetPreview(previews *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alias string, key *rsa.PrivateKey, recordHash []byte, callback PreviewCallback) error { - return bcgo.Read(previews.Name, previews.Head, nil, cache, network, alias, key, recordHash, func(entry *bcgo.BlockEntry, key, data []byte) error { +func ReadPreview(previews bcgo.Channel, cache bcgo.Cache, network bcgo.Network, account bcgo.Account, recordHash []byte, callback PreviewCallback) error { + return bcgo.Read(previews.Name(), previews.Head(), nil, cache, network, account, recordHash, func(entry *bcgo.BlockEntry, key, data []byte) error { // Unmarshal as Preview preview := &Preview{} if err := proto.Unmarshal(data, preview); err != nil { @@ -396,8 +433,8 @@ func GetPreview(previews *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, }) } -func GetTag(tags *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alias string, key *rsa.PrivateKey, recordHash []byte, callback TagCallback) error { - return bcgo.Read(tags.Name, tags.Head, nil, cache, network, alias, key, recordHash, func(entry *bcgo.BlockEntry, key, data []byte) error { +func ReadTag(tags bcgo.Channel, cache bcgo.Cache, network bcgo.Network, account bcgo.Account, recordHash []byte, callback TagCallback) error { + return bcgo.Read(tags.Name(), tags.Head(), nil, cache, network, account, recordHash, func(entry *bcgo.BlockEntry, key, data []byte) error { // Unmarshal as Tag tag := &Tag{} if err := proto.Unmarshal(data, tag); err != nil { @@ -407,29 +444,37 @@ func GetTag(tags *bcgo.Channel, cache bcgo.Cache, network bcgo.Network, alias st }) } -func GetMinimumRegistrars() int { +func MinimumRegistrars() int { if bcgo.IsLive() { return 3 } return 1 } -func IterateDeltas(node *bcgo.Node, deltas *bcgo.Channel, callback DeltaCallback) error { +func IterateDeltas(node bcgo.Node, deltas bcgo.Channel, callback DeltaCallback) error { + account := node.Account() + alias := account.Alias() // Iterate through chain chronologically - return bcgo.IterateChronologically(deltas.Name, deltas.Head, nil, node.Cache, node.Network, func(hash []byte, block *bcgo.Block) error { + return bcgo.IterateChronologically(deltas.Name(), deltas.Head(), nil, node.Cache(), node.Network(), func(hash []byte, block *bcgo.Block) error { for _, entry := range block.Entry { for _, access := range entry.Record.Access { - if node.Alias == access.Alias { - if err := bcgo.DecryptRecord(entry, access, node.Key, func(entry *bcgo.BlockEntry, key []byte, data []byte) error { - // Unmarshal as Delta - d := &Delta{} - if err := proto.Unmarshal(data, d); err != nil { - return err - } - return callback(entry, d) - }); err != nil { + if alias == access.Alias { + decryptedKey, err := account.DecryptKey(access.EncryptionAlgorithm, access.SecretKey) + if err != nil { + return err + } + decryptedPayload, err := account.Decrypt(entry.Record.EncryptionAlgorithm, entry.Record.Payload, decryptedKey) + if err != nil { return err } + // Unmarshal as Delta + d := &Delta{} + if err := proto.Unmarshal(decryptedPayload, d); err != nil { + return err + } + if err := callback(entry, d); err != nil { + return nil + } } } } diff --git a/vendor/fyne.io/fyne/v2/CHANGELOG.md b/vendor/fyne.io/fyne/v2/CHANGELOG.md index 5e46023..50ad3e8 100644 --- a/vendor/fyne.io/fyne/v2/CHANGELOG.md +++ b/vendor/fyne.io/fyne/v2/CHANGELOG.md @@ -3,6 +3,80 @@ This file lists the main changes with each version of the Fyne toolkit. More detailed release notes can be found on the [releases page](https://github.com/fyne-io/fyne/releases). +## 2.0.2 - 1 April 2021 + +### Changed + +* Text can now be copied from a disable Entry using keyboard shortcuts + +### Fixed + +* Slider offset position could be incorrect for mobile apps +* Correct error in example code +* When graphics init fails then don't try to continue running (#1593) +* Don't show global settings on mobile in fyne_demo as it's not supported (#2062) +* Empty selection would render small rectangle in Entry +* Do not show validation state for disabled Entry +* dialog.ShowFileSave did not support mobile (#2076) +* Fix issue that storage could not write to files on iOS and Android +* mobile app could crash in some focus calls +* Duplicate symbol error when compiling for Android with NDK 23 (#2064) +* Add internet permission by default for Android apps (#1715) +* Child and Parent support in storage were missing for mobile appps +* Various crashes with Entry and multiline selections (including #1989) +* Slider calls OnChanged for each value between steps (#1748) +* fyne command doesn't remove temporary binary from src (#1910) +* Advanced Color picker on mobile keeps updating values forever after sliding (#2075) +* exec.Command and widget.Button combination not working (#1857) +* After clicking a link on macOS, click everywhere in the app will be linked (#2112) +* Text selection - Shift+Tab bug (#1787) + + +## 2.0.1 - 4 March 2021 + +### Changed + +* An Entry with `Wrapping=fyne.TextWrapOff` no longer blocks scroll events from a parent + +### Fixed + +* Dialog.Resize() has no effect if called before Dialog.Show() (#1863) +* SelectTab does not always correctly set the blue underline to the selected tab (#1872) +* Entry Validation Broken when using Data binding (#1890) +* Fix background colour not applying until theme change +* android runtime error with fyne.dialog (#1896) +* Fix scale calculations for Wayland phones (PinePhone) +* Correct initial state of entry validation +* fix entry widget mouse drag selection when scrolled +* List widget panic when refreshing after changing content length (#1864) +* Fix image caching that was too agressive on resize +* Pointer and cursor misalignment in widget.Entry (#1937) +* SIGSEGV Sometimes When Closing a Program by Clicking a Button (#1604) +* Advanced Color Picker shows Black for custom primary color as RGBA (#1970) +* Canvas.Focus() before window visible causes application to crash (#1893) +* Menu over Content (#1973) +* Error compiling fyne on Apple M1 arm64 (#1739) +* Cells are not getting draw in correct location after column resize. (#1951) +* Possible panic when selecting text in a widget.Entry (#1983) +* Form validation doesn't enable submit button (#1965) +* Creating a window shows it before calling .Show() and .Hide() does not work (#1835) +* Dialogs are not refreshed correctly on .Show() (#1866) +* Failed creating setting storage : no such directory (#2023) +* Erroneous custom filter types not supported error on mobile (#2012) +* High importance button show no hovered state (#1785) +* List widget does not render all visible content after content data gets shorter (#1948) +* Calling Select on List before draw can crash (#1960) +* Dialog not resizing in newly created window (#1692) +* Dialog not returning to requested size (#1382) +* Entry without scrollable content prevents scrolling of outside scroller (#1939) +* fyne_demo crash after selecting custom Theme and table (#2018) +* Table widget crash when scrolling rapidly (#1887) +* Cursor animation sometimes distorts the text (#1778) +* Extended password entry panics when password revealer is clicked (#2036) +* Data binding limited to 1024 simultaneous operations (#1838) +* Custom theme does not refresh when variant changes (#2006) + + ## 2.0 - 22 January 2021 ### Changes that are not backward compatible @@ -89,7 +163,6 @@ The import path is now `fyne.io/fyne/v2` when you are ready to make the update. * Properly align Label in FormItem (#1531) * Mobile dropdowns are too low (#1771) * Cursor does not go down to next line with wrapping (#1737) -* MacOS Notifications are not shown on subsequent app runs after first run due to duplicate identifier (#1699) * Entry: while adding text beyond visible reagion there is no auto-scroll (#912) diff --git a/vendor/fyne.io/fyne/v2/README.md b/vendor/fyne.io/fyne/v2/README.md index 6553cb8..27908ea 100644 --- a/vendor/fyne.io/fyne/v2/README.md +++ b/vendor/fyne.io/fyne/v2/README.md @@ -1,6 +1,6 @@

Go API Reference - 2.0.0 release + 2.0.2 release Join us on Slack
Code Status @@ -10,7 +10,7 @@ # About -[Fyne](https://fyne.io) is an easy to use UI toolkit and app API written in Go. +[Fyne](https://fyne.io) is an easy-to-use UI toolkit and app API written in Go. It is designed to build applications that run on desktop and mobile devices with a single codebase. @@ -42,13 +42,19 @@ To run a showcase of the features of Fyne execute the following: And you should see something like this (after you click a few buttons):

- Fyne Hello Light Theme + Fyne Demo Dark Theme

Or if you are using the light theme:

- Fyne Hello Light Theme + Fyne Demo Light Theme +

+ +And even running on a mobile device: + +

+ Fyne Demo Mobile Light Theme

# Getting Started @@ -86,7 +92,7 @@ func main() { And you can run that simply as: - go run main.go + $ go run main.go It should look like this: @@ -103,6 +109,12 @@ It should look like this: > Note that Windows applications load from a command prompt by default, which means if you click an icon you may see a command window. > To fix this add the parameters `-ldflags -H=windowsgui` to your run or build commands. +## Run in mobile simulation + +There is a helpful mobile simulation mode that gives a hint of how your app would work on a mobile device: + + $ go run -tags mobile main.go + # Installing Using `go install` will copy the executable into your go `bin` dir. @@ -112,7 +124,17 @@ application location you can use the fyne utility and the "install" subcommand. $ go get fyne.io/fyne/v2/cmd/fyne $ fyne install -# Packaging a release +# Packaging for mobile + +To run on a mobile device it is necessary to package up the application. +To do this we can use the fyne utility "package" subcommand. +You will need to add appropriate parameters as prompted, but the basic command is shown below. +Once packaged you can install using the platform development tools or the fyne "install" subcommand. + + $ fyne package -os android -appID my.domain.appname + $ fyne install -os android + +# Preparing a release Using the fyne utility "release" subcommand you can package up your app for release to app stores and market places. Make sure you have the standard build tools installed diff --git a/vendor/fyne.io/fyne/v2/app/app.go b/vendor/fyne.io/fyne/v2/app/app.go index dbc338b..b8c85ff 100644 --- a/vendor/fyne.io/fyne/v2/app/app.go +++ b/vendor/fyne.io/fyne/v2/app/app.go @@ -90,6 +90,9 @@ func (app *fyneApp) Storage() fyne.Storage { } func (app *fyneApp) Preferences() fyne.Preferences { + if app.uniqueID == "" { + fyne.LogError("Preferences API requires a unique ID, use app.NewWithID()", nil) + } return app.prefs } diff --git a/vendor/fyne.io/fyne/v2/app/app_mobile_and.go b/vendor/fyne.io/fyne/v2/app/app_mobile_and.go index e68aa82..29d9657 100644 --- a/vendor/fyne.io/fyne/v2/app/app_mobile_and.go +++ b/vendor/fyne.io/fyne/v2/app/app_mobile_and.go @@ -16,6 +16,7 @@ import ( "log" "net/url" "os" + "path/filepath" "unsafe" mobileApp "github.com/fyne-io/mobile/app" @@ -54,5 +55,5 @@ func rootConfigDir() string { return "/data/data" // probably won't work, but we can't make a better guess } - return filesDir + return filepath.Join(filesDir, "fyne") } diff --git a/vendor/fyne.io/fyne/v2/app/preferences_android.go b/vendor/fyne.io/fyne/v2/app/preferences_android.go index 7118f5f..663abd2 100644 --- a/vendor/fyne.io/fyne/v2/app/preferences_android.go +++ b/vendor/fyne.io/fyne/v2/app/preferences_android.go @@ -7,12 +7,12 @@ import "path/filepath" // storagePath returns the location of the settings storage func (p *preferences) storagePath() string { // we have no global storage, use app global instead - rootConfigDir looks up in app_mobile_and.go - return filepath.Join(rootConfigDir(), "storage", "preferences.json") + return filepath.Join(p.app.storageRoot(), "preferences.json") } // storageRoot returns the location of the app storage func (a *fyneApp) storageRoot() string { - return filepath.Join(rootConfigDir(), a.uniqueID) + return rootConfigDir() // we are in a sandbox, so no app ID added to this path } func (p *preferences) watch() { diff --git a/vendor/fyne.io/fyne/v2/app/settings.go b/vendor/fyne.io/fyne/v2/app/settings.go index 8da8ccc..0107899 100644 --- a/vendor/fyne.io/fyne/v2/app/settings.go +++ b/vendor/fyne.io/fyne/v2/app/settings.go @@ -139,26 +139,36 @@ func (s *settings) fileChanged() { } func (s *settings) setupTheme() { - if s.themeSpecified { - return - } name := s.schema.ThemeName if env := os.Getenv("FYNE_THEME"); env != "" { - s.themeSpecified = true name = env } - if name == "light" { - s.applyTheme(theme.LightTheme(), theme.VariantLight) - } else if name == "dark" { - s.applyTheme(theme.DarkTheme(), theme.VariantDark) - } else { - if defaultVariant() == theme.VariantLight { - s.applyTheme(theme.LightTheme(), theme.VariantLight) - } else { - s.applyTheme(theme.DarkTheme(), theme.VariantDark) + var variant fyne.ThemeVariant + effectiveTheme := s.theme + switch name { + case "light": + variant = theme.VariantLight + if !s.themeSpecified { + effectiveTheme = theme.LightTheme() + } + case "dark": + variant = theme.VariantDark + if !s.themeSpecified { + effectiveTheme = theme.DarkTheme() + } + default: + variant = defaultVariant() + if s.themeSpecified { + break + } + effectiveTheme = theme.DarkTheme() + if variant == theme.VariantLight { + effectiveTheme = theme.LightTheme() } } + + s.applyTheme(effectiveTheme, variant) } func loadSettings() *settings { diff --git a/vendor/fyne.io/fyne/v2/app/settings_desktop.go b/vendor/fyne.io/fyne/v2/app/settings_desktop.go index 6f7f785..0a9b342 100644 --- a/vendor/fyne.io/fyne/v2/app/settings_desktop.go +++ b/vendor/fyne.io/fyne/v2/app/settings_desktop.go @@ -25,7 +25,7 @@ func ensureDirExists(dir string) { return } - err := os.Mkdir(dir, 0700) + err := os.MkdirAll(dir, 0700) if err != nil { fyne.LogError("Unable to create settings storage:", err) } diff --git a/vendor/fyne.io/fyne/v2/canvas/base.go b/vendor/fyne.io/fyne/v2/canvas/base.go index da2ff35..d7b5d3f 100644 --- a/vendor/fyne.io/fyne/v2/canvas/base.go +++ b/vendor/fyne.io/fyne/v2/canvas/base.go @@ -14,8 +14,8 @@ import ( ) type baseObject struct { - size fyne.Size // The current size of the Rectangle - position fyne.Position // The current position of the Rectangle + size fyne.Size // The current size of the canvas object + position fyne.Position // The current position of the object Hidden bool // Is this object currently hidden min fyne.Size // The minimum size this object can be @@ -23,7 +23,7 @@ type baseObject struct { propertyLock sync.RWMutex } -// CurrentSize returns the current size of this rectangle object +// CurrentSize returns the current size of this canvas object. func (r *baseObject) Size() fyne.Size { r.propertyLock.RLock() defer r.propertyLock.RUnlock() @@ -31,7 +31,7 @@ func (r *baseObject) Size() fyne.Size { return r.size } -// Resize sets a new size for the rectangle object +// Resize sets a new size for the canvas object. func (r *baseObject) Resize(size fyne.Size) { r.propertyLock.Lock() defer r.propertyLock.Unlock() @@ -39,7 +39,7 @@ func (r *baseObject) Resize(size fyne.Size) { r.size = size } -// CurrentPosition gets the current position of this rectangle object, relative to its parent / canvas +// CurrentPosition gets the current position of this canvas object, relative to its parent. func (r *baseObject) Position() fyne.Position { r.propertyLock.RLock() defer r.propertyLock.RUnlock() @@ -47,7 +47,7 @@ func (r *baseObject) Position() fyne.Position { return r.position } -// Move the rectangle object to a new position, relative to its parent / canvas +// Move the object to a new position, relative to its parent. func (r *baseObject) Move(pos fyne.Position) { r.propertyLock.Lock() defer r.propertyLock.Unlock() @@ -55,7 +55,7 @@ func (r *baseObject) Move(pos fyne.Position) { r.position = pos } -// MinSize returns the specified minimum size, if set, or {1, 1} otherwise +// MinSize returns the specified minimum size, if set, or {1, 1} otherwise. func (r *baseObject) MinSize() fyne.Size { r.propertyLock.RLock() defer r.propertyLock.RUnlock() @@ -67,7 +67,7 @@ func (r *baseObject) MinSize() fyne.Size { return r.min } -// SetMinSize specifies the smallest size this object should be +// SetMinSize specifies the smallest size this object should be. func (r *baseObject) SetMinSize(size fyne.Size) { r.propertyLock.Lock() defer r.propertyLock.Unlock() @@ -75,7 +75,7 @@ func (r *baseObject) SetMinSize(size fyne.Size) { r.min = size } -// IsVisible returns true if this object is visible, false otherwise +// IsVisible returns true if this object is visible, false otherwise. func (r *baseObject) Visible() bool { r.propertyLock.RLock() defer r.propertyLock.RUnlock() @@ -83,7 +83,7 @@ func (r *baseObject) Visible() bool { return !r.Hidden } -// Show will set this object to be visible +// Show will set this object to be visible. func (r *baseObject) Show() { r.propertyLock.Lock() defer r.propertyLock.Unlock() @@ -91,7 +91,7 @@ func (r *baseObject) Show() { r.Hidden = false } -// Hide will set this object to not be visible +// Hide will set this object to not be visible. func (r *baseObject) Hide() { r.propertyLock.Lock() defer r.propertyLock.Unlock() diff --git a/vendor/fyne.io/fyne/v2/canvas/image.go b/vendor/fyne.io/fyne/v2/canvas/image.go index 01c6683..53d4e6c 100644 --- a/vendor/fyne.io/fyne/v2/canvas/image.go +++ b/vendor/fyne.io/fyne/v2/canvas/image.go @@ -68,15 +68,16 @@ func (i *Image) Alpha() float64 { return 1.0 - i.Translucency } -// Resize on an image will usually scale the content or reposition it according to FillMode.. -// If the content of the File or Resource is an SVG file, however, this will cause a Refresh. +// Resize on an image will scale the content or reposition it according to FillMode. +// It will normally cause a Refresh to ensure the pixels are recalculated. func (i *Image) Resize(s fyne.Size) { + if s == i.Size() { + return + } + i.baseObject.Resize(s) - if (i.File != "" && filepath.Ext(i.File) == ".svg") || - (i.Resource != nil && filepath.Ext(i.Resource.Name()) == ".svg") { - Refresh(i) - } + Refresh(i) } // Refresh causes this object to be redrawn in it's current state diff --git a/vendor/fyne.io/fyne/v2/canvas/raster.go b/vendor/fyne.io/fyne/v2/canvas/raster.go index 50972cb..9f80903 100644 --- a/vendor/fyne.io/fyne/v2/canvas/raster.go +++ b/vendor/fyne.io/fyne/v2/canvas/raster.go @@ -34,6 +34,10 @@ func (r *Raster) Alpha() float64 { // Resize on a raster image causes the new size to be set and then calls Refresh. // This causes the underlying data to be recalculated and a new output to be drawn. func (r *Raster) Resize(s fyne.Size) { + if s == r.Size() { + return + } + r.baseObject.Resize(s) Refresh(r) } diff --git a/vendor/fyne.io/fyne/v2/container/apptabs.go b/vendor/fyne.io/fyne/v2/container/apptabs.go index 9f2631e..ccebc08 100644 --- a/vendor/fyne.io/fyne/v2/container/apptabs.go +++ b/vendor/fyne.io/fyne/v2/container/apptabs.go @@ -56,7 +56,7 @@ func NewAppTabs(items ...*TabItem) *AppTabs { // Current is first tab item tabs.current = 0 } - tabs.ExtendBaseWidget(tabs) + tabs.BaseWidget.ExtendBaseWidget(tabs) if tabs.mismatchedContent() { internal.LogHint("AppTabs items should all have the same type of content (text, icons or both)") @@ -86,7 +86,7 @@ func (c *AppTabs) Append(item *TabItem) { // CreateRenderer is a private method to Fyne which links this widget to its renderer func (c *AppTabs) CreateRenderer() fyne.WidgetRenderer { - c.ExtendBaseWidget(c) + c.BaseWidget.ExtendBaseWidget(c) r := &appTabsRenderer{line: canvas.NewRectangle(theme.ShadowColor()), underline: canvas.NewRectangle(theme.PrimaryColor()), container: c} r.updateTabs() @@ -106,9 +106,16 @@ func (c *AppTabs) CurrentTabIndex() int { return c.current } +// ExtendBaseWidget is used by an extending widget to make use of BaseWidget functionality. +// +// Deprecated: Support for extending containers is being removed +func (c *AppTabs) ExtendBaseWidget(wid fyne.Widget) { + c.BaseWidget.ExtendBaseWidget(wid) +} + // MinSize returns the size that this widget should not shrink below func (c *AppTabs) MinSize() fyne.Size { - c.ExtendBaseWidget(c) + c.BaseWidget.ExtendBaseWidget(c) return c.BaseWidget.MinSize() } @@ -380,24 +387,28 @@ func (r *appTabsRenderer) moveSelection() { } r.underline.Show() - if r.underline.Position().IsZero() || r.underline.Position() == underlinePos { + if r.underline.Position().IsZero() { r.underline.Move(underlinePos) r.underline.Resize(underlineSize) - } else if r.animation == nil { - r.animation = canvas.NewPositionAnimation(r.underline.Position(), underlinePos, canvas.DurationShort, func(p fyne.Position) { - r.underline.Move(p) - canvas.Refresh(r.underline) - if p == underlinePos { - r.animation = nil - } - }) - r.animation.Start() + return + } - canvas.NewSizeAnimation(r.underline.Size(), underlineSize, canvas.DurationShort, func(s fyne.Size) { - r.underline.Resize(s) - canvas.Refresh(r.underline) - }).Start() + if r.animation != nil { + r.animation.Stop() } + r.animation = canvas.NewPositionAnimation(r.underline.Position(), underlinePos, canvas.DurationShort, func(p fyne.Position) { + r.underline.Move(p) + canvas.Refresh(r.underline) + if p == underlinePos { + r.animation = nil + } + }) + r.animation.Start() + + canvas.NewSizeAnimation(r.underline.Size(), underlineSize, canvas.DurationShort, func(s fyne.Size) { + r.underline.Resize(s) + canvas.Refresh(r.underline) + }).Start() } func (r *appTabsRenderer) tabsInSync() bool { diff --git a/vendor/fyne.io/fyne/v2/container/split.go b/vendor/fyne.io/fyne/v2/container/split.go index 10fdbdc..caef2e8 100644 --- a/vendor/fyne.io/fyne/v2/container/split.go +++ b/vendor/fyne.io/fyne/v2/container/split.go @@ -45,13 +45,13 @@ func newSplitContainer(horizontal bool, leading, trailing fyne.CanvasObject) *Sp Leading: leading, Trailing: trailing, } - s.ExtendBaseWidget(s) + s.BaseWidget.ExtendBaseWidget(s) return s } // CreateRenderer is a private method to Fyne which links this widget to its renderer func (s *Split) CreateRenderer() fyne.WidgetRenderer { - s.ExtendBaseWidget(s) + s.BaseWidget.ExtendBaseWidget(s) d := newDivider(s) return &splitContainerRenderer{ split: s, @@ -60,6 +60,13 @@ func (s *Split) CreateRenderer() fyne.WidgetRenderer { } } +// ExtendBaseWidget is used by an extending widget to make use of BaseWidget functionality. +// +// Deprecated: Support for extending containers is being removed +func (s *Split) ExtendBaseWidget(wid fyne.Widget) { + s.BaseWidget.ExtendBaseWidget(wid) +} + // SetOffset sets the offset (0.0 to 1.0) of the Split divider. // 0.0 - Leading is min size, Trailing uses all remaining space. // 0.5 - Leading & Trailing equally share the available space. diff --git a/vendor/fyne.io/fyne/v2/data/binding/queue.go b/vendor/fyne.io/fyne/v2/data/binding/queue.go index 7587a88..cafaed5 100644 --- a/vendor/fyne.io/fyne/v2/data/binding/queue.go +++ b/vendor/fyne.io/fyne/v2/data/binding/queue.go @@ -1,6 +1,6 @@ package binding -var itemQueue = make(chan itemData, 1024) +var itemQueueIn, itemQueueOut = makeInfiniteQueue() type itemData struct { fn func() @@ -8,16 +8,50 @@ type itemData struct { } func queueItem(f func()) { - itemQueue <- itemData{fn: f} + itemQueueIn <- &itemData{fn: f} } func init() { go processItems() } +func makeInfiniteQueue() (chan<- *itemData, <-chan *itemData) { + in := make(chan *itemData) + out := make(chan *itemData) + go func() { + queued := make([]*itemData, 0, 1024) + pending := func() chan *itemData { + if len(queued) == 0 { + return nil + } + return out + } + next := func() *itemData { + if len(queued) == 0 { + return nil + } + return queued[0] + } + for len(queued) > 0 || in != nil { + select { + case val, ok := <-in: + if !ok { + in = nil + } else { + queued = append(queued, val) + } + case pending() <- next(): + queued = queued[1:] + } + } + close(out) + }() + return in, out +} + func processItems() { for { - i := <-itemQueue + i := <-itemQueueOut if i.fn != nil { i.fn() } @@ -29,6 +63,6 @@ func processItems() { func waitForItems() { done := make(chan interface{}) - itemQueue <- itemData{done: done} + itemQueueIn <- &itemData{done: done} <-done } diff --git a/vendor/fyne.io/fyne/v2/dialog/base.go b/vendor/fyne.io/fyne/v2/dialog/base.go index b375fec..3c7c742 100644 --- a/vendor/fyne.io/fyne/v2/dialog/base.go +++ b/vendor/fyne.io/fyne/v2/dialog/base.go @@ -31,12 +31,13 @@ type Dialog interface { var _ Dialog = (*dialog)(nil) type dialog struct { - callback func(bool) - title string - icon fyne.Resource + callback func(bool) + title string + icon fyne.Resource + desiredSize fyne.Size win *widget.PopUp - bg *canvas.Rectangle + bg *themedBackground content, label fyne.CanvasObject dismiss *widget.Button parent fyne.Window @@ -99,6 +100,9 @@ func (d *dialog) Hide() { } func (d *dialog) Show() { + if !d.desiredSize.IsZero() { + d.win.Resize(d.desiredSize) + } d.win.Show() } @@ -106,7 +110,7 @@ func (d *dialog) Layout(obj []fyne.CanvasObject, size fyne.Size) { d.bg.Move(fyne.NewPos(0, 0)) d.bg.Resize(size) - btnMin := obj[3].MinSize().Max(obj[3].Size()) + btnMin := obj[3].MinSize() // icon iconHeight := padHeight*2 + d.label.MinSize().Height*2 - theme.Padding() @@ -126,7 +130,7 @@ func (d *dialog) Layout(obj []fyne.CanvasObject, size fyne.Size) { func (d *dialog) MinSize(obj []fyne.CanvasObject) fyne.Size { contentMin := obj[2].MinSize() - btnMin := obj[3].MinSize().Max(obj[3].Size()) + btnMin := obj[3].MinSize() width := fyne.Max(fyne.Max(contentMin.Width, btnMin.Width), obj[4].MinSize().Width) + padWidth height := contentMin.Height + btnMin.Height + d.label.MinSize().Height + theme.Padding() + padHeight*2 @@ -135,27 +139,13 @@ func (d *dialog) MinSize(obj []fyne.CanvasObject) fyne.Size { } func (d *dialog) Refresh() { - d.applyTheme() d.win.Refresh() } // Resize dialog, call this function after dialog show func (d *dialog) Resize(size fyne.Size) { - maxSize := d.win.Size() - minSize := d.win.MinSize() - newWidth := size.Width - if size.Width > maxSize.Width { - newWidth = maxSize.Width - } else if size.Width < minSize.Width { - newWidth = minSize.Width - } - newHeight := size.Height - if size.Height > maxSize.Height { - newHeight = maxSize.Height - } else if size.Height < minSize.Height { - newHeight = minSize.Height - } - d.win.Resize(fyne.NewSize(newWidth, newHeight)) + d.desiredSize = size + d.win.Resize(size) } // SetDismissText allows custom text to be set in the confirmation button @@ -178,12 +168,6 @@ func (d *dialog) SetOnClosed(closed func()) { } } -func (d *dialog) applyTheme() { - r, g, b, _ := theme.BackgroundColor().RGBA() - bg := &color.NRGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 230} - d.bg.FillColor = bg -} - func (d *dialog) hideWithResponse(resp bool) { d.win.Hide() if d.callback != nil { @@ -192,8 +176,8 @@ func (d *dialog) hideWithResponse(resp bool) { } func (d *dialog) setButtons(buttons fyne.CanvasObject) { - d.bg = canvas.NewRectangle(theme.BackgroundColor()) - d.label = newDialogTitle(d.title, d) + d.bg = newThemedBackground() + d.label = widget.NewLabelWithStyle(d.title, fyne.TextAlignLeading, fyne.TextStyle{Bold: true}) var content fyne.CanvasObject if d.icon == nil { @@ -240,27 +224,52 @@ func newButtonList(buttons ...*widget.Button) fyne.CanvasObject { return list } -// dialogTitle is really just a normal title but we use the Refresh() hook to update the background rectangle. -type dialogTitle struct { - widget.Label +// =============================================================== +// ThemedBackground +// =============================================================== + +type themedBackground struct { + widget.BaseWidget +} + +func newThemedBackground() *themedBackground { + t := &themedBackground{} + t.ExtendBaseWidget(t) + return t +} + +func (t *themedBackground) CreateRenderer() fyne.WidgetRenderer { + t.ExtendBaseWidget(t) + rect := canvas.NewRectangle(theme.BackgroundColor()) + return &themedBackgroundRenderer{rect, []fyne.CanvasObject{rect}} +} + +type themedBackgroundRenderer struct { + rect *canvas.Rectangle + objects []fyne.CanvasObject +} - d *dialog +func (renderer *themedBackgroundRenderer) Destroy() { } -// Refresh applies the current theme to the whole dialog before refreshing the underlying label. -func (t *dialogTitle) Refresh() { - t.d.Refresh() +func (renderer *themedBackgroundRenderer) Layout(size fyne.Size) { + renderer.rect.Resize(size) +} - t.BaseWidget.Refresh() +func (renderer *themedBackgroundRenderer) MinSize() fyne.Size { + return renderer.rect.MinSize() } -func newDialogTitle(title string, d *dialog) *dialogTitle { - l := &dialogTitle{} - l.Text = title - l.Alignment = fyne.TextAlignLeading - l.TextStyle.Bold = true +func (renderer *themedBackgroundRenderer) Objects() []fyne.CanvasObject { + return renderer.objects +} - l.d = d - l.ExtendBaseWidget(l) - return l +func (renderer *themedBackgroundRenderer) Refresh() { + r, g, b, _ := theme.BackgroundColor().RGBA() + bg := &color.NRGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 230} + renderer.rect.FillColor = bg } + +// =============================================================== +// DialogLayout +// =============================================================== diff --git a/vendor/fyne.io/fyne/v2/dialog/color.go b/vendor/fyne.io/fyne/v2/dialog/color.go index 0cfdf4d..aff4bd3 100644 --- a/vendor/fyne.io/fyne/v2/dialog/color.go +++ b/vendor/fyne.io/fyne/v2/dialog/color.go @@ -243,17 +243,7 @@ func colorToRGBA(c color.Color) (r, g, b, a int) { b = int(col.B) a = int(col.A) default: - red, green, blue, alpha := c.RGBA() - if alpha != 0 && alpha != 1 { - red /= alpha - green /= alpha - blue /= alpha - } - // Convert from range 0-65535 to range 0-255 - r = int(float64(red) / 255.0) - g = int(float64(green) / 255.0) - b = int(float64(blue) / 255.0) - a = int(float64(alpha) / 255.0) + r, g, b, a = unmultiplyAlpha(c) } return } @@ -352,3 +342,19 @@ func hueToChannel(h, v1, v2 float64) float64 { } return v2 } + +func unmultiplyAlpha(c color.Color) (r, g, b, a int) { + red, green, blue, alpha := c.RGBA() + if alpha != 0 && alpha != 0xffff { + ratio := float64(alpha) / 0xffff + red = uint32(float64(red) / ratio) + green = uint32(float64(green) / ratio) + blue = uint32(float64(blue) / ratio) + } + // Convert from range 0-65535 to range 0-255 + r = int(red >> 8) + g = int(green >> 8) + b = int(blue >> 8) + a = int(alpha >> 8) + return +} diff --git a/vendor/fyne.io/fyne/v2/dialog/color_channel.go b/vendor/fyne.io/fyne/v2/dialog/color_channel.go index 313698c..6ab7d31 100644 --- a/vendor/fyne.io/fyne/v2/dialog/color_channel.go +++ b/vendor/fyne.io/fyne/v2/dialog/color_channel.go @@ -2,6 +2,7 @@ package dialog import ( "strconv" + "sync" "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" @@ -124,25 +125,21 @@ func (r *colorChannelRenderer) updateObjects() { } type colorChannelEntry struct { - widget.Entry + userChangeEntry } func newColorChannelEntry(c *colorChannel) *colorChannelEntry { - e := &colorChannelEntry{ - Entry: widget.Entry{ - Text: "0", - OnChanged: func(text string) { - value, err := strconv.Atoi(text) - if err != nil { - fyne.LogError("Couldn't parse: "+text, err) - } else { - c.SetValue(value) - } - }, - // TODO add number min/max validator - }, - } + e := &colorChannelEntry{} + e.Text = "0" e.ExtendBaseWidget(e) + e.setOnChanged(func(text string) { + value, err := strconv.Atoi(text) + if err != nil { + fyne.LogError("Couldn't parse: "+text, err) + return + } + c.SetValue(value) + }) return e } @@ -152,3 +149,49 @@ func (e *colorChannelEntry) MinSize() fyne.Size { min = min.Add(fyne.NewSize(theme.Padding()*6, theme.Padding()*4)) return min.Max(e.Entry.MinSize()) } + +type userChangeEntry struct { + widget.Entry + + lock sync.RWMutex + userTyped bool +} + +func newUserChangeEntry(text string) *userChangeEntry { + e := &userChangeEntry{} + e.Entry.Text = text + e.ExtendBaseWidget(e) + return e +} + +func (e *userChangeEntry) setOnChanged(onChanged func(s string)) { + e.Entry.OnChanged = func(text string) { + e.lock.Lock() + userTyped := e.userTyped + if userTyped { + e.userTyped = false + } + e.lock.Unlock() + if !userTyped { + return + } + if onChanged != nil { + onChanged(text) + } + } + e.ExtendBaseWidget(e) +} + +func (e *userChangeEntry) TypedRune(r rune) { + e.lock.Lock() + e.userTyped = true + e.lock.Unlock() + e.Entry.TypedRune(r) +} + +func (e *userChangeEntry) TypedKey(ev *fyne.KeyEvent) { + e.lock.Lock() + e.userTyped = true + e.lock.Unlock() + e.Entry.TypedKey(ev) +} diff --git a/vendor/fyne.io/fyne/v2/dialog/color_picker.go b/vendor/fyne.io/fyne/v2/dialog/color_picker.go index 835c9fa..6c0a784 100644 --- a/vendor/fyne.io/fyne/v2/dialog/color_picker.go +++ b/vendor/fyne.io/fyne/v2/dialog/color_picker.go @@ -162,17 +162,16 @@ func (p *colorAdvancedPicker) CreateRenderer() fyne.WidgetRenderer { }) // Hex - hex := &widget.Entry{ - OnChanged: func(text string) { - c, err := stringToColor(text) - if err != nil { - fyne.LogError("Error parsing color: "+text, err) - // TODO trigger entry invalid state - } else { - p.SetColor(c) - } - }, - } + hex := newUserChangeEntry("") + hex.setOnChanged(func(text string) { + c, err := stringToColor(text) + if err != nil { + fyne.LogError("Error parsing color: "+text, err) + // TODO trigger entry invalid state + } else { + p.SetColor(c) + } + }) contents := fyne.NewContainerWithLayout(layout.NewPaddedLayout(), container.NewVBox( container.NewGridWithColumns(3, @@ -264,7 +263,7 @@ type colorPickerRenderer struct { wheel *colorWheel preview *canvas.Rectangle alphaChannel *colorChannel - hex *widget.Entry + hex *userChangeEntry contents fyne.CanvasObject } diff --git a/vendor/fyne.io/fyne/v2/dialog/file.go b/vendor/fyne.io/fyne/v2/dialog/file.go index d81c620..247e57b 100644 --- a/vendor/fyne.io/fyne/v2/dialog/file.go +++ b/vendor/fyne.io/fyne/v2/dialog/file.go @@ -47,7 +47,7 @@ type FileDialog struct { parent fyne.Window dialog *fileDialog dismissText string - desiredSize *fyne.Size + desiredSize fyne.Size // this will be applied to dialog.dir when it's loaded startingLocation fyne.ListableURI // this will be the initial filename in a FileDialog in save mode @@ -459,9 +459,8 @@ func (f *FileDialog) Show() { return } f.dialog = showFile(f) - if f.desiredSize != nil { - f.Resize(*f.desiredSize) - f.desiredSize = nil + if !f.desiredSize.IsZero() { + f.Resize(f.desiredSize) } } @@ -470,27 +469,14 @@ func (f *FileDialog) Refresh() { f.dialog.win.Refresh() } -// Resize dialog, call this function after dialog show +// Resize dialog to the requested size, if there is sufficient space. +// If the parent window is not large enough then the size will be reduced to fit. func (f *FileDialog) Resize(size fyne.Size) { + f.desiredSize = size if f.dialog == nil { - f.desiredSize = &size return } - maxSize := f.dialog.win.Size() - minSize := f.dialog.win.MinSize() - newWidth := size.Width - if size.Width > maxSize.Width { - newWidth = maxSize.Width - } else if size.Width < minSize.Width { - newWidth = minSize.Width - } - newHeight := size.Height - if size.Height > maxSize.Height { - newHeight = maxSize.Height - } else if size.Height < minSize.Height { - newHeight = minSize.Height - } - f.dialog.win.Resize(fyne.NewSize(newWidth, newHeight)) + f.dialog.win.Resize(size) } // Hide hides the file dialog. diff --git a/vendor/fyne.io/fyne/v2/dialog/file_mobile.go b/vendor/fyne.io/fyne/v2/dialog/file_mobile.go index 8e9350f..6e31497 100644 --- a/vendor/fyne.io/fyne/v2/dialog/file_mobile.go +++ b/vendor/fyne.io/fyne/v2/dialog/file_mobile.go @@ -36,12 +36,7 @@ func fileOpenOSOverride(f *FileDialog) bool { } func fileSaveOSOverride(f *FileDialog) bool { - ShowInformation("File Save", "File save not available on mobile", f.parent) - - callback := f.callback.(func(fyne.URIWriteCloser, error)) - if callback != nil { - callback(nil, nil) - } + gomobile.ShowFileSavePicker(f.callback.(func(fyne.URIWriteCloser, error)), f.filter) return true } diff --git a/vendor/fyne.io/fyne/v2/dialog/progress.go b/vendor/fyne.io/fyne/v2/dialog/progress.go index 72da379..56386c0 100644 --- a/vendor/fyne.io/fyne/v2/dialog/progress.go +++ b/vendor/fyne.io/fyne/v2/dialog/progress.go @@ -1,7 +1,11 @@ package dialog import ( + "image/color" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" ) @@ -27,8 +31,9 @@ func (p *ProgressDialog) SetValue(v float64) { func NewProgress(title, message string, parent fyne.Window) *ProgressDialog { d := newDialog(title, message, theme.InfoIcon(), nil /*cancel?*/, parent) bar := widget.NewProgressBar() - bar.Resize(fyne.NewSize(200, bar.MinSize().Height)) + rect := canvas.NewRectangle(color.Transparent) + rect.SetMinSize(fyne.NewSize(200, 0)) - d.setButtons(bar) + d.setButtons(container.NewMax(rect, bar)) return &ProgressDialog{d, bar} } diff --git a/vendor/fyne.io/fyne/v2/dialog/progressinfinite.go b/vendor/fyne.io/fyne/v2/dialog/progressinfinite.go index af937f0..a780907 100644 --- a/vendor/fyne.io/fyne/v2/dialog/progressinfinite.go +++ b/vendor/fyne.io/fyne/v2/dialog/progressinfinite.go @@ -1,7 +1,11 @@ package dialog import ( + "image/color" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" ) @@ -22,9 +26,10 @@ type ProgressInfiniteDialog struct { func NewProgressInfinite(title, message string, parent fyne.Window) *ProgressInfiniteDialog { d := newDialog(title, message, theme.InfoIcon(), nil /*cancel?*/, parent) bar := widget.NewProgressBarInfinite() - bar.Resize(fyne.NewSize(200, bar.MinSize().Height)) + rect := canvas.NewRectangle(color.Transparent) + rect.SetMinSize(fyne.NewSize(200, 0)) - d.setButtons(bar) + d.setButtons(container.NewMax(rect, bar)) return &ProgressInfiniteDialog{d, bar} } diff --git a/vendor/fyne.io/fyne/v2/driver.go b/vendor/fyne.io/fyne/v2/driver.go index e425614..b9be762 100644 --- a/vendor/fyne.io/fyne/v2/driver.go +++ b/vendor/fyne.io/fyne/v2/driver.go @@ -22,6 +22,7 @@ type Driver interface { // Run starts the main event loop of the driver. Run() // Quit closes the driver and open windows, then exit the application. + // On some some operating systems this does nothing, for example iOS and Android. Quit() // StartAnimation registers a new animation with this driver and requests it be started. diff --git a/vendor/fyne.io/fyne/v2/fyne.go b/vendor/fyne.io/fyne/v2/fyne.go index 36cb439..0e37b34 100644 --- a/vendor/fyne.io/fyne/v2/fyne.go +++ b/vendor/fyne.io/fyne/v2/fyne.go @@ -8,6 +8,7 @@ // package main // // import "fyne.io/fyne/v2/app" +// import "fyne.io/fyne/v2/container" // import "fyne.io/fyne/v2/widget" // // func main() { @@ -15,7 +16,7 @@ // w := a.NewWindow("Hello") // // hello := widget.NewLabel("Hello Fyne!") -// w.SetContent(widget.NewVBox( +// w.SetContent(container.NewVBox( // hello, // widget.NewButton("Hi!", func() { // hello.SetText("Welcome :)") diff --git a/vendor/fyne.io/fyne/v2/go.mod b/vendor/fyne.io/fyne/v2/go.mod index 07c2308..7648888 100644 --- a/vendor/fyne.io/fyne/v2/go.mod +++ b/vendor/fyne.io/fyne/v2/go.mod @@ -5,11 +5,11 @@ go 1.12 require ( github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9 github.com/akavel/rsrc v0.8.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 github.com/fsnotify/fsnotify v1.4.9 - github.com/fyne-io/mobile v0.1.2 + github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 - github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3 + github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48 github.com/godbus/dbus/v5 v5.0.3 github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526 @@ -28,7 +28,4 @@ require ( golang.org/x/tools v0.0.0-20200328031815-3db5fc6bac03 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v2 v2.2.8 // indirect - github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 ) - -replace github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3 => github.com/fyne-io/glfw/v3.3/glfw v0.0.0-20201123143003-f2279069162d diff --git a/vendor/fyne.io/fyne/v2/go.sum b/vendor/fyne.io/fyne/v2/go.sum index 112f526..74eb476 100644 --- a/vendor/fyne.io/fyne/v2/go.sum +++ b/vendor/fyne.io/fyne/v2/go.sum @@ -10,12 +10,12 @@ github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8 github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fyne-io/glfw/v3.3/glfw v0.0.0-20201123143003-f2279069162d h1:WfVxpuVm+5Gr3ipAoWrxV8lJFYkaBWoEwFRrWThWRSU= -github.com/fyne-io/glfw/v3.3/glfw v0.0.0-20201123143003-f2279069162d/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/fyne-io/mobile v0.1.2 h1:0HaXDtOOwyOTn3Umi0uKVCOgJtfX73c6unC4U8i5VZU= -github.com/fyne-io/mobile v0.1.2/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY= +github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f h1:rguJ/t99j/6zRSFzsBKlsmmyl+vOvCeTJ+2uTBvuXFI= +github.com/fyne-io/mobile v0.1.3-0.20210318200029-09e9c4e13a8f/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY= github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw= github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48 h1:QrUfZrT8n72FUuiABt4tbu8PwDnOPAbnj3Mql1UhdRI= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210311203641-62640a716d48/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8= @@ -44,7 +44,6 @@ github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQO github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4= github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM= github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU= -github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= @@ -52,14 +51,12 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/yuin/goldmark v1.1.25/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/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= @@ -72,18 +69,15 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666 h1:gVCS+QOncANNPlmlO1AhlU3oxs4V9z+gTtPwIk3p2N8= golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190808195139-e713427fea3f h1:lSQQYboXWc71s9tnZRRBiMcc9Uc1BPWj3Bzvdk8UQ0Y= golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/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-20200328031815-3db5fc6bac03 h1:XpToik3MpT5iW3iHgNwnh3a8QwugfomvxOlyDnaOils= golang.org/x/tools v0.0.0-20200328031815-3db5fc6bac03/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/fyne.io/fyne/v2/internal/animation/animation.go b/vendor/fyne.io/fyne/v2/internal/animation/animation.go index 2464551..9c4656b 100644 --- a/vendor/fyne.io/fyne/v2/internal/animation/animation.go +++ b/vendor/fyne.io/fyne/v2/internal/animation/animation.go @@ -1,6 +1,7 @@ package animation import ( + "sync" "time" "fyne.io/fyne/v2" @@ -13,6 +14,9 @@ type anim struct { reverse bool start time.Time total int64 + + mu sync.RWMutex + stopped bool } func newAnim(a *fyne.Animation) *anim { @@ -21,3 +25,16 @@ func newAnim(a *fyne.Animation) *anim { animate.repeatsLeft = a.RepeatCount return animate } + +func (a *anim) setStopped() { + a.mu.Lock() + a.stopped = true + a.mu.Unlock() +} + +func (a *anim) isStopped() bool { + a.mu.RLock() + ret := a.stopped + a.mu.RUnlock() + return ret +} diff --git a/vendor/fyne.io/fyne/v2/internal/animation/runner.go b/vendor/fyne.io/fyne/v2/internal/animation/runner.go index 6b72977..764b062 100644 --- a/vendor/fyne.io/fyne/v2/internal/animation/runner.go +++ b/vendor/fyne.io/fyne/v2/internal/animation/runner.go @@ -9,19 +9,24 @@ import ( // Runner is the main driver for animations package type Runner struct { - animationMutex sync.RWMutex - animations []*anim + animationMutex sync.RWMutex + animations []*anim + pendingAnimations []*anim + + runnerStarted bool } // Start will register the passed application and initiate its ticking. func (r *Runner) Start(a *fyne.Animation) { r.animationMutex.Lock() defer r.animationMutex.Unlock() - wasStopped := len(r.animations) == 0 - r.animations = append(r.animations, newAnim(a)) - if wasStopped { + if !r.runnerStarted { + r.runnerStarted = true + r.animations = append(r.animations, newAnim(a)) r.runAnimations() + } else { + r.pendingAnimations = append(r.pendingAnimations, newAnim(a)) } } @@ -29,14 +34,31 @@ func (r *Runner) Start(a *fyne.Animation) { func (r *Runner) Stop(a *fyne.Animation) { r.animationMutex.Lock() defer r.animationMutex.Unlock() - oldList := r.animations - var newList []*anim - for _, item := range oldList { + + newList := make([]*anim, 0, len(r.animations)) + stopped := false + for _, item := range r.animations { if item.a != a { newList = append(newList, item) + } else { + item.setStopped() + stopped = true } } r.animations = newList + if stopped { + return + } + + newList = make([]*anim, 0, len(r.pendingAnimations)) + for _, item := range r.pendingAnimations { + if item.a != a { + newList = append(newList, item) + } else { + item.setStopped() + } + } + r.pendingAnimations = newList } func (r *Runner) runAnimations() { @@ -47,19 +69,22 @@ func (r *Runner) runAnimations() { <-draw.C r.animationMutex.Lock() oldList := r.animations - r.animations = nil // clear the list so we can append any new ones after processing r.animationMutex.Unlock() - var newList []*anim + newList := make([]*anim, 0, len(oldList)) for _, a := range oldList { - if r.tickAnimation(a) { + if !a.isStopped() && r.tickAnimation(a) { newList = append(newList, a) } } r.animationMutex.Lock() - r.animations = append(newList, r.animations...) + r.animations = append(newList, r.pendingAnimations...) + r.pendingAnimations = nil done = len(r.animations) == 0 r.animationMutex.Unlock() } + r.animationMutex.Lock() + r.runnerStarted = false + r.animationMutex.Unlock() draw.Stop() }() } @@ -90,6 +115,7 @@ func (r *Runner) tickAnimation(a *anim) bool { a.start = time.Now() a.end = a.start.Add(a.a.Duration) + return true } delta := time.Since(a.start).Nanoseconds() / 1000000 // TODO change this to Milliseconds() when we drop Go 1.12 diff --git a/vendor/fyne.io/fyne/v2/internal/app/focus_manager.go b/vendor/fyne.io/fyne/v2/internal/app/focus_manager.go index 1eff4bb..cd86b3d 100644 --- a/vendor/fyne.io/fyne/v2/internal/app/focus_manager.go +++ b/vendor/fyne.io/fyne/v2/internal/app/focus_manager.go @@ -52,7 +52,12 @@ func (f *FocusManager) Focus(obj fyne.Focusable) bool { return true } if dis, ok := obj.(fyne.Disableable); ok && dis.Disabled() { - return true + type selectableText interface { + SelectedText() string + } + if _, isSelectableText := obj.(selectableText); !isSelectableText || fyne.CurrentDevice().IsMobile() { + return true + } } } f.focus(obj) diff --git a/vendor/fyne.io/fyne/v2/internal/driver/glfw/canvas.go b/vendor/fyne.io/fyne/v2/internal/driver/glfw/canvas.go index 265763c..ae6c305 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/glfw/canvas.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/glfw/canvas.go @@ -84,12 +84,16 @@ func (c *glCanvas) Focus(obj fyne.Focusable) { c.RUnlock() for _, mgr := range focusMgrs { + if mgr == nil { + continue + } if focusMgr != mgr { if mgr.Focus(obj) { return } } } + fyne.LogError("Failed to focus object which is not part of the canvas’ content, menu or overlays.", nil) } @@ -178,7 +182,7 @@ func (c *glCanvas) Resize(size fyne.Size) { if p, ok := overlay.(*widget.PopUp); ok { // TODO: remove this when #707 is being addressed. // “Notifies” the PopUp of the canvas size change. - p.Resize(p.Content.Size().Add(fyne.NewSize(theme.Padding()*2, theme.Padding()*2))) + p.Refresh() } else { overlay.Resize(size) } @@ -452,7 +456,14 @@ func (c *glCanvas) paint(size fyne.Size) { func (c *glCanvas) setContent(content fyne.CanvasObject) { c.content = content c.contentTree = &renderCacheTree{root: &renderCacheNode{obj: c.content}} + var focused fyne.Focusable + if c.contentFocusMgr != nil { + focused = c.contentFocusMgr.Focused() // keep old focus if possible + } c.contentFocusMgr = app.NewFocusManager(c.content) + if focused != nil { + c.contentFocusMgr.Focus(focused) + } } func (c *glCanvas) setDirty(dirty bool) { @@ -466,6 +477,14 @@ func (c *glCanvas) setMenuOverlay(b fyne.CanvasObject) { c.menu = b c.menuTree = &renderCacheTree{root: &renderCacheNode{obj: c.menu}} c.menuFocusMgr = app.NewFocusManager(c.menu) + + if c.menu != nil && !c.size.IsZero() { + c.content.Resize(c.contentSize(c.size)) + c.content.Move(c.contentPos()) + + c.menu.Refresh() + c.menu.Resize(fyne.NewSize(c.size.Width, c.menu.MinSize().Height)) + } } func (c *glCanvas) setupThemeListener() { diff --git a/vendor/fyne.io/fyne/v2/internal/driver/glfw/driver.go b/vendor/fyne.io/fyne/v2/internal/driver/glfw/driver.go index 4964b5c..7eef211 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/glfw/driver.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/glfw/driver.go @@ -3,6 +3,7 @@ package glfw import ( + "os" "runtime" "strconv" "strings" @@ -113,6 +114,16 @@ func (d *gLDriver) windowList() []fyne.Window { return d.windows } +func (d *gLDriver) initFailed(msg string, err error) { + fyne.LogError(msg, err) + + if running() { + d.Quit() + } else { + os.Exit(1) + } +} + func goroutineID() int { b := make([]byte, 64) b = b[:runtime.Stack(b, false)] diff --git a/vendor/fyne.io/fyne/v2/internal/driver/glfw/glfw_core.go b/vendor/fyne.io/fyne/v2/internal/driver/glfw/glfw_core.go index 8c57655..3646b37 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/glfw/glfw_core.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/glfw/glfw_core.go @@ -1,4 +1,4 @@ -// +build !gles,!arm,!arm64 +// +build !gles,!arm,!arm64 darwin package glfw diff --git a/vendor/fyne.io/fyne/v2/internal/driver/glfw/glfw_es.go b/vendor/fyne.io/fyne/v2/internal/driver/glfw/glfw_es.go index afeac02..c389c92 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/glfw/glfw_es.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/glfw/glfw_es.go @@ -1,4 +1,5 @@ // +build gles arm arm64 +// +build !darwin package glfw diff --git a/vendor/fyne.io/fyne/v2/internal/driver/glfw/loop.go b/vendor/fyne.io/fyne/v2/internal/driver/glfw/loop.go index f76d69d..69e4fd3 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/glfw/loop.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/glfw/loop.go @@ -113,7 +113,6 @@ func (d *gLDriver) runGL() { w.viewLock.Lock() w.visible = false v := w.viewport - w.viewport = nil w.viewLock.Unlock() // remove window from window list @@ -201,10 +200,10 @@ func (d *gLDriver) startDrawThread() { w := win.(*window) w.viewLock.RLock() canvas := w.canvas - view := w.viewport + closing := w.closing visible := w.visible w.viewLock.RUnlock() - if view == nil || !canvas.isDirty() || !visible { + if closing || !canvas.isDirty() || !visible { continue } diff --git a/vendor/fyne.io/fyne/v2/internal/driver/glfw/window.go b/vendor/fyne.io/fyne/v2/internal/driver/glfw/window.go index baf63bf..b3d41b2 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/glfw/window.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/glfw/window.go @@ -51,11 +51,13 @@ type window struct { viewLock sync.RWMutex createLock sync.Once decorate bool + closing bool fixedSize bool cursor desktop.Cursor customCursor *glfw.Cursor canvas *glCanvas + driver *gLDriver title string icon fyne.Resource mainmenu *fyne.MainMenu @@ -273,7 +275,7 @@ func (w *window) fitContent() { return } - if w.viewport == nil { + if w.isClosing() { return } @@ -405,7 +407,7 @@ func (w *window) doShow() { } func (w *window) Hide() { - if w.viewport == nil { + if w.isClosing() { return } @@ -423,10 +425,11 @@ func (w *window) Hide() { } func (w *window) Close() { - if w.viewport == nil { + if w.isClosing() { return } + w.closing = true w.viewport.SetShouldClose(true) w.canvas.walkTrees(nil, func(node *renderCacheNode) { @@ -444,12 +447,12 @@ func (w *window) Close() { func (w *window) ShowAndRun() { w.Show() - fyne.CurrentApp().Driver().Run() + w.driver.Run() } // Clipboard returns the system clipboard func (w *window) Clipboard() fyne.Clipboard { - if w.viewport == nil { + if w.view() == nil { return nil } @@ -699,6 +702,11 @@ func (w *window) mouseOut() { } func (w *window) mouseClicked(_ *glfw.Window, btn glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) { + if w.mousePos.IsZero() { // window may not be focused (darwin mostly) and so position callbacks not happening + xpos, ypos := w.viewport.GetCursorPos() + w.mousePos = fyne.NewPos(internal.UnscaleInt(w.canvas, int(xpos)), internal.UnscaleInt(w.canvas, int(ypos))) + } + co, pos, _ := w.findObjectAtPositionMatching(w.canvas, w.mousePos, func(object fyne.CanvasObject) bool { switch object.(type) { case fyne.Tappable, fyne.SecondaryTappable, fyne.DoubleTappable, fyne.Focusable, desktop.Mouseable, desktop.Hoverable: @@ -1121,10 +1129,19 @@ func (w *window) keyPressed(_ *glfw.Window, key glfw.Key, scancode int, action g if shortcut != nil { if focused, ok := w.canvas.Focused().(fyne.Shortcutable); ok { - w.queueEvent(func() { focused.TypedShortcut(shortcut) }) + shouldRunShortcut := true + type selectableText interface { + fyne.Disableable + SelectedText() string + } + if selectableTextWid, ok := focused.(selectableText); ok && selectableTextWid.Disabled() { + shouldRunShortcut = shortcut.ShortcutName() == "Copy" + } + if shouldRunShortcut { + w.queueEvent(func() { focused.TypedShortcut(shortcut) }) + } return } - w.queueEvent(func() { w.canvas.shortcut.TypedShortcut(shortcut) }) return } @@ -1172,10 +1189,14 @@ func (w *window) focused(_ *glfw.Window, isFocused bool) { w.canvas.FocusGained() } else { w.canvas.FocusLost() + w.mousePos = fyne.Position{} } } func (w *window) RunWithContext(f func()) { + if w.isClosing() { + return + } w.viewport.MakeContextCurrent() f() @@ -1190,7 +1211,7 @@ func (w *window) RescaleContext() { } func (w *window) rescaleOnMain() { - if w.viewport == nil { + if w.isClosing() { return } w.fitContent() @@ -1260,7 +1281,7 @@ func (d *gLDriver) createWindow(title string, decorate bool) fyne.Window { runOnMain(func() { d.initGLFW() - ret = &window{title: title, decorate: decorate} + ret = &window{title: title, decorate: decorate, driver: d} // This channel will be closed when the window is closed. ret.eventQueue = make(chan func(), 1024) go ret.runEventQueue() @@ -1303,7 +1324,7 @@ func (w *window) create() { win, err := glfw.CreateWindow(pixWidth, pixHeight, w.title, nil, nil) if err != nil { - fyne.LogError("window creation error", err) + w.driver.initFailed("window creation error", err) return } @@ -1354,7 +1375,7 @@ func (w *window) create() { } func (w *window) doShowAgain() { - if w.viewport == nil { + if w.isClosing() { return } @@ -1372,10 +1393,17 @@ func (w *window) doShowAgain() { }) } +func (w *window) isClosing() bool { + return w.closing || w.viewport == nil +} + func (w *window) view() *glfw.Window { w.viewLock.RLock() defer w.viewLock.RUnlock() + if w.closing { + return nil + } return w.viewport } diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/android.c b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/android.c index 930a46d..cee6f2a 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/android.c +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/android.c @@ -144,6 +144,26 @@ void* openStream(uintptr_t jni_env, uintptr_t ctx, char* uriCstr) { return (*env)->NewGlobalRef(env, stream); } +void* saveStream(uintptr_t jni_env, uintptr_t ctx, char* uriCstr) { + JNIEnv *env = (JNIEnv*)jni_env; + jobject resolver = getContentResolver(jni_env, ctx); + + jclass resolverClass = (*env)->GetObjectClass(env, resolver); + jmethodID saveOutputStream = find_method(env, resolverClass, "openOutputStream", "(Landroid/net/Uri;Ljava/lang/String;)Ljava/io/OutputStream;"); + + jobject uri = parseURI(jni_env, ctx, uriCstr); + jstring modes = (*env)->NewStringUTF(env, "wt"); // truncate before write + jobject stream = (jobject)(*env)->CallObjectMethod(env, resolver, saveOutputStream, uri, modes); + jthrowable loadErr = (*env)->ExceptionOccurred(env); + + if (loadErr != NULL) { + (*env)->ExceptionClear(env); + return NULL; + } + + return (*env)->NewGlobalRef(env, stream); +} + char* readStream(uintptr_t jni_env, uintptr_t ctx, void* stream, int len, int* total) { JNIEnv *env = (JNIEnv*)jni_env; jclass streamClass = (*env)->GetObjectClass(env, stream); @@ -162,6 +182,19 @@ char* readStream(uintptr_t jni_env, uintptr_t ctx, void* stream, int len, int* t return bytes; } +void writeStream(uintptr_t jni_env, uintptr_t ctx, void* stream, char* buf, int len) { + JNIEnv *env = (JNIEnv*)jni_env; + jclass streamClass = (*env)->GetObjectClass(env, stream); + jmethodID write = find_method(env, streamClass, "write", "([BII)V"); + + jbyteArray data = (*env)->NewByteArray(env, len); + (*env)->SetByteArrayRegion(env, data, 0, len, buf); + + (*env)->CallVoidMethod(env, stream, write, data, 0, len); + + free(buf); +} + void closeStream(uintptr_t jni_env, uintptr_t ctx, void* stream) { JNIEnv *env = (JNIEnv*)jni_env; jclass streamClass = (*env)->GetObjectClass(env, stream); @@ -183,7 +216,6 @@ bool hasPrefix(char* string, char* prefix) { bool canListContentURI(uintptr_t jni_env, uintptr_t ctx, char* uriCstr) { JNIEnv *env = (JNIEnv*)jni_env; jobject resolver = getContentResolver(jni_env, ctx); - jstring uriStr = (*env)->NewStringUTF(env, uriCstr); jobject uri = parseURI(jni_env, ctx, uriCstr); jthrowable loadErr = (*env)->ExceptionOccurred(env); @@ -243,10 +275,41 @@ bool canListURI(uintptr_t jni_env, uintptr_t ctx, char* uriCstr) { return false; } +char* contentURIGetFileName(uintptr_t jni_env, uintptr_t ctx, char* uriCstr) { + JNIEnv *env = (JNIEnv*)jni_env; + jobject resolver = getContentResolver(jni_env, ctx); + jobject uri = parseURI(jni_env, ctx, uriCstr); + jthrowable loadErr = (*env)->ExceptionOccurred(env); + + if (loadErr != NULL) { + (*env)->ExceptionClear(env); + return ""; + } + + jclass stringClass = find_class(env, "java/lang/String"); + jobjectArray project = (*env)->NewObjectArray(env, 1, stringClass, (*env)->NewStringUTF(env, "_display_name")); + + jclass resolverClass = (*env)->GetObjectClass(env, resolver); + jmethodID query = find_method(env, resolverClass, "query", "(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;"); + + jobject cursor = (jobject)(*env)->CallObjectMethod(env, resolver, query, uri, project, NULL, NULL, NULL); + jclass cursorClass = (*env)->GetObjectClass(env, cursor); + + jmethodID first = find_method(env, cursorClass, "moveToFirst", "()Z"); + jmethodID get = find_method(env, cursorClass, "getString", "(I)Ljava/lang/String;"); + + if (((jboolean)(*env)->CallBooleanMethod(env, cursor, first)) == JNI_TRUE) { + jstring name = (jstring)(*env)->CallObjectMethod(env, cursor, get, 0); + char *fname = getString(jni_env, ctx, name); + return fname; + } + + return NULL; +} + char* listContentURI(uintptr_t jni_env, uintptr_t ctx, char* uriCstr) { JNIEnv *env = (JNIEnv*)jni_env; jobject resolver = getContentResolver(jni_env, ctx); - jstring uriStr = (*env)->NewStringUTF(env, uriCstr); jobject uri = parseURI(jni_env, ctx, uriCstr); jthrowable loadErr = (*env)->ExceptionOccurred(env); diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/canvas.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/canvas.go index eeab19c..1824df2 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/canvas.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/canvas.go @@ -40,12 +40,13 @@ type mobileCanvas struct { onTypedKey func(event *fyne.KeyEvent) shortcut fyne.ShortcutHandler - inited bool - lastTapDown map[int]time.Time - lastTapDownPos map[int]fyne.Position - dragging fyne.Draggable - refreshQueue chan fyne.CanvasObject - minSizeCache map[fyne.CanvasObject]fyne.Size + inited bool + lastTapDown map[int]time.Time + lastTapDownPos map[int]fyne.Position + dragging fyne.Draggable + dragStart, dragOffset fyne.Position + refreshQueue chan fyne.CanvasObject + minSizeCache map[fyne.CanvasObject]fyne.Size touchTapCount int touchCancelFunc context.CancelFunc @@ -82,7 +83,7 @@ func (c *mobileCanvas) Content() fyne.CanvasObject { func (c *mobileCanvas) Focus(obj fyne.Focusable) { focusMgr := c.focusManager() - if focusMgr.Focus(obj) { // fast path – probably >99.9% of all cases + if focusMgr != nil && focusMgr.Focus(obj) { // fast path – probably >99.9% of all cases c.handleKeyboard(obj) return } @@ -101,15 +102,27 @@ func (c *mobileCanvas) Focus(obj fyne.Focusable) { } func (c *mobileCanvas) FocusNext() { - c.focusManager().FocusNext() + mgr := c.focusManager() + if mgr == nil { + return + } + mgr.FocusNext() } func (c *mobileCanvas) FocusPrevious() { - c.focusManager().FocusPrevious() + mgr := c.focusManager() + if mgr == nil { + return + } + mgr.FocusPrevious() } func (c *mobileCanvas) Focused() fyne.Focusable { - return c.focusManager().Focused() + mgr := c.focusManager() + if mgr == nil { + return nil + } + return mgr.Focused() } func (c *mobileCanvas) InteractiveArea() (fyne.Position, fyne.Size) { @@ -176,7 +189,11 @@ func (c *mobileCanvas) Size() fyne.Size { } func (c *mobileCanvas) Unfocus() { - if c.focusManager().Focus(nil) { + mgr := c.focusManager() + if mgr == nil { + return + } + if mgr.Focus(nil) { hideVirtualKeyboard() } } @@ -340,8 +357,7 @@ func (c *mobileCanvas) sizeContent(size fyne.Size) { if p, ok := overlay.(*widget.PopUp); ok { // TODO: remove this when #707 is being addressed. // “Notifies” the PopUp of the canvas size change. - size := p.Content.Size().Add(fyne.NewSize(theme.Padding()*2, theme.Padding()*2)).Min(areaSize) - p.Resize(size) + p.Refresh() } else { overlay.Resize(areaSize) overlay.Move(topLeft) @@ -390,8 +406,9 @@ func (c *mobileCanvas) tapDown(pos fyne.Position, tapID int) { func (c *mobileCanvas) tapMove(pos fyne.Position, tapID int, dragCallback func(fyne.Draggable, *fyne.DragEvent)) { - deltaX := pos.X - c.lastTapDownPos[tapID].X - deltaY := pos.Y - c.lastTapDownPos[tapID].Y + previousPos := c.lastTapDownPos[tapID] + deltaX := pos.X - previousPos.X + deltaY := pos.Y - previousPos.Y if c.dragging == nil && (math.Abs(float64(deltaX)) < tapMoveThreshold && math.Abs(float64(deltaY)) < tapMoveThreshold) { return @@ -421,13 +438,16 @@ func (c *mobileCanvas) tapMove(pos fyne.Position, tapID int, if c.dragging == nil { if drag, ok := co.(fyne.Draggable); ok { c.dragging = drag + c.dragOffset = previousPos.Subtract(objPos) + c.dragStart = co.Position() } else { return } } ev := new(fyne.DragEvent) - ev.Position = objPos + draggedObjDelta := c.dragStart.Subtract(c.dragging.(fyne.CanvasObject).Position()) + ev.Position = pos.Subtract(c.dragOffset).Add(draggedObjDelta) ev.Dragged = fyne.Delta{DX: deltaX, DY: deltaY} dragCallback(c.dragging, ev) diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_android.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_android.go index c78b6fc..3601a2a 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_android.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_android.go @@ -4,6 +4,8 @@ package gomobile import "fyne.io/fyne/v2" +const tapYOffset = -12.0 // to compensate for how we hold our fingers on the device + func (*device) SystemScaleForWindow(_ fyne.Window) float32 { if currentDPI >= 600 { return 4 diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_desktop.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_desktop.go index 1c5fcb8..047251b 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_desktop.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_desktop.go @@ -1,9 +1,11 @@ -// +build !ios,!android +// +build !ios,!android,!wayland package gomobile import "fyne.io/fyne/v2" +const tapYOffset = 0 // no finger compensation on desktop (simulation) + func (*device) SystemScaleForWindow(_ fyne.Window) float32 { return 2 // this is simply due to the high number of pixels on a mobile device - just an approximation } diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_ios.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_ios.go index ba2ed7a..e5270f7 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_ios.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_ios.go @@ -4,6 +4,8 @@ package gomobile import "fyne.io/fyne/v2" +const tapYOffset = -12.0 // to compensate for how we hold our fingers on the device + func (*device) SystemScaleForWindow(_ fyne.Window) float32 { if currentDPI >= 450 { return 3 diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_wayland.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_wayland.go new file mode 100644 index 0000000..c2ce3bb --- /dev/null +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/device_wayland.go @@ -0,0 +1,9 @@ +// +build wayland + +package gomobile + +import "fyne.io/fyne/v2" + +func (*device) SystemScaleForWindow(_ fyne.Window) float32 { + return 1 // PinePhone simplification, our only wayland mobile currently +} diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/driver.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/driver.go index d5ba90d..4a428f5 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/driver.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/driver.go @@ -26,7 +26,6 @@ import ( const ( tapMoveThreshold = 4.0 // how far can we move before it is a drag tapSecondaryDelay = 300 * time.Millisecond // how long before secondary tap - tapYOffset = -12.0 // to compensate for how we hold our fingers on the device ) type mobileDriver struct { @@ -64,7 +63,15 @@ func (d *mobileDriver) currentWindow() fyne.Window { return nil } - return d.windows[len(d.windows)-1] + var last fyne.Window + for i := len(d.windows) - 1; i >= 0; i-- { + last = d.windows[i] + if last.(*window).visible { + return last + } + } + + return last } func (d *mobileDriver) RenderedTextSize(text string, size float32, style fyne.TextStyle) fyne.Size { diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file.go index 8afe32e..ea12251 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file.go @@ -36,27 +36,27 @@ func mobileFilter(filter storage.FileFilter) *app.FileFilter { mobile.MimeTypes = f.MimeTypes } else if f, ok := filter.(*storage.ExtensionFileFilter); ok { mobile.Extensions = f.Extensions - } else { + } else if filter != nil { fyne.LogError("Custom filter types not supported on mobile", nil) } return mobile } -type hasPicker interface { +type hasOpenPicker interface { ShowFileOpenPicker(func(string, func()), *app.FileFilter) } // ShowFileOpenPicker loads the native file open dialog and returns the chosen file path via the callback func. func ShowFileOpenPicker(callback func(fyne.URIReadCloser, error), filter storage.FileFilter) { drv := fyne.CurrentApp().Driver().(*mobileDriver) - if a, ok := drv.app.(hasPicker); ok { + if a, ok := drv.app.(hasOpenPicker); ok { a.ShowFileOpenPicker(func(uri string, closer func()) { if uri == "" { callback(nil, nil) return } - f, err := fileReaderForURI(storage.NewURI(uri)) + f, err := fileReaderForURI(nativeURI(uri)) if f != nil { f.(*fileOpen).done = closer } @@ -69,7 +69,7 @@ func ShowFileOpenPicker(callback func(fyne.URIReadCloser, error), filter storage func ShowFolderOpenPicker(callback func(fyne.ListableURI, error)) { filter := storage.NewMimeTypeFileFilter([]string{"application/x-directory"}) drv := fyne.CurrentApp().Driver().(*mobileDriver) - if a, ok := drv.app.(hasPicker); ok { + if a, ok := drv.app.(hasOpenPicker); ok { a.ShowFileOpenPicker(func(uri string, _ func()) { if uri == "" { callback(nil, nil) @@ -80,3 +80,45 @@ func ShowFolderOpenPicker(callback func(fyne.ListableURI, error)) { }, mobileFilter(filter)) } } + +type fileSave struct { + io.WriteCloser + uri fyne.URI + done func() +} + +func (f *fileSave) URI() fyne.URI { + return f.uri +} + +func fileWriterForURI(u fyne.URI) (fyne.URIWriteCloser, error) { + file := &fileSave{uri: u} + write, err := nativeFileSave(file) + if write == nil { + return nil, err + } + file.WriteCloser = write + return file, err +} + +type hasSavePicker interface { + ShowFileSavePicker(func(string, func()), *app.FileFilter) +} + +// ShowFileSavePicker loads the native file save dialog and returns the chosen file path via the callback func. +func ShowFileSavePicker(callback func(fyne.URIWriteCloser, error), filter storage.FileFilter) { + drv := fyne.CurrentApp().Driver().(*mobileDriver) + if a, ok := drv.app.(hasSavePicker); ok { + a.ShowFileSavePicker(func(uri string, closer func()) { + if uri == "" { + callback(nil, nil) + return + } + f, err := fileWriterForURI(storage.NewURI(uri)) + if f != nil { + f.(*fileSave).done = closer + } + callback(f, err) + }, mobileFilter(filter)) + } +} diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_android.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_android.go index 5c69c8a..4becae0 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_android.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_android.go @@ -9,6 +9,8 @@ package gomobile void* openStream(uintptr_t jni_env, uintptr_t ctx, char* uriCstr); char* readStream(uintptr_t jni_env, uintptr_t ctx, void* stream, int len, int* total); +void* saveStream(uintptr_t jni_env, uintptr_t ctx, char* uriCstr); +void writeStream(uintptr_t jni_env, uintptr_t ctx, void* stream, char* data, int len); void closeStream(uintptr_t jni_env, uintptr_t ctx, void* stream); */ import "C" @@ -92,8 +94,52 @@ func nativeFileOpen(f *fileOpen) (io.ReadCloser, error) { return stream, nil } +func saveStream(uri string) unsafe.Pointer { + uriStr := C.CString(uri) + defer C.free(unsafe.Pointer(uriStr)) + + var stream unsafe.Pointer + app.RunOnJVM(func(_, env, ctx uintptr) error { + streamPtr := C.saveStream(C.uintptr_t(env), C.uintptr_t(ctx), uriStr) + if streamPtr == C.NULL { + return os.ErrNotExist + } + + stream = unsafe.Pointer(streamPtr) + return nil + }) + return stream +} + +func nativeFileSave(f *fileSave) (io.WriteCloser, error) { + if f.uri == nil || f.uri.String() == "" { + return nil, nil + } + + ret := saveStream(f.uri.String()) + if ret == nil { + return nil, errors.New("resource not found at URI") + } + + stream := &javaStream{} + stream.stream = ret + return stream, nil +} + +// Declare conformity to WriteCloser interface +var _ io.WriteCloser = (*javaStream)(nil) + +func (s *javaStream) Write(p []byte) (int, error) { + err := app.RunOnJVM(func(_, env, ctx uintptr) error { + C.writeStream(C.uintptr_t(env), C.uintptr_t(ctx), s.stream, (*C.char)(C.CBytes(p)), C.int(len(p))) + return nil + }) + + return len(p), err +} + func registerRepository(d *mobileDriver) { - repo := &mobileFileRepo{driver: d} + repo := &mobileFileRepo{} repository.Register("file", repo) repository.Register("content", repo) } diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_desktop.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_desktop.go index d883357..ba84061 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_desktop.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_desktop.go @@ -14,6 +14,11 @@ func nativeFileOpen(*fileOpen) (io.ReadCloser, error) { return nil, nil } +func nativeFileSave(*fileSave) (io.WriteCloser, error) { + // no-op as we use the internal FileRepository + return nil, nil +} + func registerRepository(d *mobileDriver) { repository.Register("file", intRepo.NewFileRepository()) } diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_ios.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_ios.go index 21cc476..528c7a5 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_ios.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_ios.go @@ -10,6 +10,7 @@ package gomobile void* iosParseUrl(const char* url); const void* iosReadFromURL(void* url, int* len); +const int iosWriteToURL(void* url, const void* bytes, int len); */ import "C" import ( @@ -63,6 +64,31 @@ func (s *secureReadCloser) Close() error { return nil } +type secureWriteCloser struct { + url unsafe.Pointer + closer func() + + offset int +} + +// Declare conformity to WriteCloser interface +var _ io.WriteCloser = (*secureWriteCloser)(nil) + +func (s *secureWriteCloser) Write(p []byte) (int, error) { + count := int(C.iosWriteToURL(s.url, C.CBytes(p), C.int(len(p)))) + s.offset += count + + return count, nil +} + +func (s *secureWriteCloser) Close() error { + if s.closer != nil { + s.closer() + } + s.url = nil + return nil +} + func nativeFileOpen(f *fileOpen) (io.ReadCloser, error) { if f.uri == nil || f.uri.String() == "" { return nil, nil @@ -77,7 +103,21 @@ func nativeFileOpen(f *fileOpen) (io.ReadCloser, error) { return fileStruct, nil } +func nativeFileSave(f *fileSave) (io.WriteCloser, error) { + if f.uri == nil || f.uri.String() == "" { + return nil, nil + } + + cStr := C.CString(f.uri.String()) + defer C.free(unsafe.Pointer(cStr)) + + url := C.iosParseUrl(cStr) + + fileStruct := &secureWriteCloser{url: url, closer: f.done} + return fileStruct, nil +} + func registerRepository(d *mobileDriver) { - repo := &mobileFileRepo{driver: d} + repo := &mobileFileRepo{} repository.Register("file", repo) } diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_ios.m b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_ios.m index 864e209..613cf0a 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_ios.m +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/file_ios.m @@ -16,3 +16,14 @@ *len = data.length; return data.bytes; } + +const int iosWriteToURL(void* urlPtr, const void* bytes, int len) { + NSURL* url = (NSURL*)urlPtr; + NSData *data = [NSData dataWithBytes:bytes length:len]; + BOOL ok = [data writeToURL:url atomically:YES]; + + if (!ok) { + return 0; + } + return data.length; +} diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/keyboard.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/keyboard.go index 967878b..d414357 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/keyboard.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/keyboard.go @@ -8,12 +8,21 @@ import ( func showVirtualKeyboard(keyboard mobile.KeyboardType) { if driver, ok := fyne.CurrentApp().Driver().(*mobileDriver); ok { + if driver.app == nil { // not yet running + fyne.LogError("Cannot show keyboard before app is running", nil) + return + } + driver.app.ShowVirtualKeyboard(app.KeyboardType(keyboard)) } } func hideVirtualKeyboard() { if driver, ok := fyne.CurrentApp().Driver().(*mobileDriver); ok { + if driver.app == nil { // not yet running + return + } + driver.app.HideVirtualKeyboard() } } diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/repository.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/repository.go index 4b2d33f..29fb537 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/repository.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/repository.go @@ -1,5 +1,3 @@ -// +build ios android - package gomobile import ( @@ -10,39 +8,66 @@ import ( // declare conformance with repository types var _ repository.Repository = (*mobileFileRepo)(nil) +var _ repository.HierarchicalRepository = (*mobileFileRepo)(nil) var _ repository.ListableRepository = (*mobileFileRepo)(nil) - -// TODO add write support (not yet supported on mobile) -// var _ repository.WritableRepository = (*mobileFileRepo)(nil) +var _ repository.WritableRepository = (*mobileFileRepo)(nil) type mobileFileRepo struct { - driver *mobileDriver -} - -func (m *mobileFileRepo) Exists(u fyne.URI) (bool, error) { - return true, nil // TODO check a file exists } -func (m *mobileFileRepo) Reader(u fyne.URI) (fyne.URIReadCloser, error) { - return fileReaderForURI(u) +func (m *mobileFileRepo) CanList(u fyne.URI) (bool, error) { + return canListURI(u), nil } func (m *mobileFileRepo) CanRead(u fyne.URI) (bool, error) { return true, nil // TODO check a file can be read } +func (m *mobileFileRepo) CanWrite(u fyne.URI) (bool, error) { + return true, nil // TODO check a file can be written +} + +func (m *mobileFileRepo) Child(u fyne.URI, name string) (fyne.URI, error) { + if u == nil || u.Scheme() != "file" { + return nil, repository.ErrOperationNotSupported + } + + return repository.GenericChild(u, name) +} + +func (m *mobileFileRepo) CreateListable(u fyne.URI) error { + // TODO: implement this + return repository.ErrOperationNotSupported +} + +func (m *mobileFileRepo) Delete(u fyne.URI) error { + // TODO: implement this + return repository.ErrOperationNotSupported +} + func (m *mobileFileRepo) Destroy(string) { } -func (m *mobileFileRepo) CanList(u fyne.URI) (bool, error) { - return canListURI(u), nil +func (m *mobileFileRepo) Exists(u fyne.URI) (bool, error) { + return true, nil // TODO check a file exists } func (m *mobileFileRepo) List(u fyne.URI) ([]fyne.URI, error) { return listURI(u) } -func (m *mobileFileRepo) CreateListable(u fyne.URI) error { - // TODO: implement this - return repository.ErrOperationNotSupported +func (m *mobileFileRepo) Parent(u fyne.URI) (fyne.URI, error) { + if u == nil || u.Scheme() != "file" { + return nil, repository.ErrOperationNotSupported + } + + return repository.GenericParent(u) +} + +func (m *mobileFileRepo) Reader(u fyne.URI) (fyne.URIReadCloser, error) { + return fileReaderForURI(u) +} + +func (m *mobileFileRepo) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { + return fileWriterForURI(u) } diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/uri.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/uri.go new file mode 100644 index 0000000..dadfc50 --- /dev/null +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/uri.go @@ -0,0 +1,12 @@ +// +build !android + +package gomobile + +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" +) + +func nativeURI(uri string) fyne.URI { + return storage.NewURI(uri) +} diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/uri_android.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/uri_android.go new file mode 100644 index 0000000..b113874 --- /dev/null +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/uri_android.go @@ -0,0 +1,63 @@ +// +build android + +package gomobile + +/* +#cgo LDFLAGS: -landroid -llog + +#include + +char* contentURIGetFileName(uintptr_t jni_env, uintptr_t ctx, char* uriCstr); +*/ +import "C" +import ( + "path/filepath" + "unsafe" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" + "github.com/fyne-io/mobile/app" +) + +type androidURI struct { + systemURI string + fyne.URI +} + +// Override Name on android for content:// +func (a *androidURI) Name() string { + if a.Scheme() == "content" { + result := contentURIGetFileName(a.systemURI) + if result != "" { + return result + } + } + return a.URI.Name() +} + +func (a *androidURI) Extension() string { + return filepath.Ext(a.Name()) +} + +func contentURIGetFileName(uri string) string { + uriStr := C.CString(uri) + defer C.free(unsafe.Pointer(uriStr)) + + var filename string + app.RunOnJVM(func(_, env, ctx uintptr) error { + fnamePtr := C.contentURIGetFileName(C.uintptr_t(env), C.uintptr_t(ctx), uriStr) + vPtr := unsafe.Pointer(fnamePtr) + if vPtr == C.NULL { + return nil + } + filename = C.GoString(fnamePtr) + C.free(vPtr) + + return nil + }) + return filename +} + +func nativeURI(uri string) fyne.URI { + return &androidURI{URI: storage.NewURI(uri), systemURI: uri} +} diff --git a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/window.go b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/window.go index 8bc00a3..cfb6f65 100644 --- a/vendor/fyne.io/fyne/v2/internal/driver/gomobile/window.go +++ b/vendor/fyne.io/fyne/v2/internal/driver/gomobile/window.go @@ -121,6 +121,7 @@ func (w *window) Show() { w.visible = true if w.Content() != nil { + w.Content().Refresh() w.Content().Show() } } diff --git a/vendor/fyne.io/fyne/v2/internal/painter/gl/gl_core.go b/vendor/fyne.io/fyne/v2/internal/painter/gl/gl_core.go index b7f5e49..34196f8 100644 --- a/vendor/fyne.io/fyne/v2/internal/painter/gl/gl_core.go +++ b/vendor/fyne.io/fyne/v2/internal/painter/gl/gl_core.go @@ -1,4 +1,4 @@ -// +build !gles,!arm,!arm64,!android,!ios,!mobile +// +build !gles,!arm,!arm64,!android,!ios,!mobile darwin,!mobile,!ios package gl diff --git a/vendor/fyne.io/fyne/v2/internal/painter/gl/gl_es.go b/vendor/fyne.io/fyne/v2/internal/painter/gl/gl_es.go index 817ffe9..5ff64a4 100644 --- a/vendor/fyne.io/fyne/v2/internal/painter/gl/gl_es.go +++ b/vendor/fyne.io/fyne/v2/internal/painter/gl/gl_es.go @@ -1,5 +1,6 @@ // +build gles arm arm64 // +build !android,!ios,!mobile +// +build !darwin package gl diff --git a/vendor/fyne.io/fyne/v2/internal/widget/scroller.go b/vendor/fyne.io/fyne/v2/internal/widget/scroller.go index 504132d..2a70885 100644 --- a/vendor/fyne.io/fyne/v2/internal/widget/scroller.go +++ b/vendor/fyne.io/fyne/v2/internal/widget/scroller.go @@ -402,6 +402,9 @@ func (r *scrollContainerRenderer) handleShadowVisibility(offset, contentSize, sc } func (r *scrollContainerRenderer) updatePosition() { + if r.scroll.Content == nil { + return + } scrollSize := r.scroll.Size() contentSize := r.scroll.Content.Size() diff --git a/vendor/fyne.io/fyne/v2/test/testcanvas.go b/vendor/fyne.io/fyne/v2/test/testcanvas.go index 24ac67b..1bb95e3 100644 --- a/vendor/fyne.io/fyne/v2/test/testcanvas.go +++ b/vendor/fyne.io/fyne/v2/test/testcanvas.go @@ -160,8 +160,19 @@ func (c *testCanvas) Resize(size fyne.Size) { return } + // Ensure testcanvas mimics real canvas.Resize behavior for _, overlay := range overlays.List() { - overlay.Resize(size) + type popupWidget interface { + fyne.CanvasObject + ShowAtPosition(fyne.Position) + } + if p, ok := overlay.(popupWidget); ok { + // TODO: remove this when #707 is being addressed. + // “Notifies” the PopUp of the canvas size change. + p.Refresh() + } else { + overlay.Resize(size) + } } if padded { diff --git a/vendor/fyne.io/fyne/v2/widget/button.go b/vendor/fyne.io/fyne/v2/widget/button.go index 5c2ecbc..07e3902 100644 --- a/vendor/fyne.io/fyne/v2/widget/button.go +++ b/vendor/fyne.io/fyne/v2/widget/button.go @@ -312,10 +312,25 @@ func (r *buttonRenderer) buttonColor() color.Color { switch { case r.button.Disabled(): return theme.DisabledButtonColor() + case r.button.hovered: + bg := theme.ButtonColor() + if r.button.Importance == HighImportance { + bg = theme.PrimaryColor() + } + + dstR, dstG, dstB, dstA := bg.RGBA() + srcR, srcG, srcB, srcA := theme.HoverColor().RGBA() + srcAlpha := float32(srcA) / 0xFFFF + dstAlpha := float32(dstA) / 0xFFFF + targetAlpha := 1 - srcAlpha*dstAlpha + + outAlpha := srcAlpha + targetAlpha + outR := (srcAlpha*float32(srcR) + targetAlpha*float32(dstR)) / outAlpha + outG := (srcAlpha*float32(srcG) + targetAlpha*float32(dstG)) / outAlpha + outB := (srcAlpha*float32(srcB) + targetAlpha*float32(dstB)) / outAlpha + return color.RGBA{R: uint8(uint32(outR) >> 8), G: uint8(uint32(outG) >> 8), B: uint8(uint32(outB) >> 8), A: uint8(outAlpha * 0xFF)} case r.button.Importance == HighImportance: return theme.PrimaryColor() - case r.button.hovered: - return theme.HoverColor() default: return theme.ButtonColor() } diff --git a/vendor/fyne.io/fyne/v2/widget/entry.go b/vendor/fyne.io/fyne/v2/widget/entry.go index 41a51ba..9b838a9 100644 --- a/vendor/fyne.io/fyne/v2/widget/entry.go +++ b/vendor/fyne.io/fyne/v2/widget/entry.go @@ -4,7 +4,6 @@ import ( "image/color" "math" "strings" - "time" "unicode" "fyne.io/fyne/v2" @@ -57,6 +56,8 @@ type Entry struct { CursorRow, CursorColumn int OnCursorChanged func() `json:"-"` + cursorAnim *entryCursorAnimation + focused bool text *textProvider placeholder *textProvider @@ -131,7 +132,7 @@ func (e *Entry) Bind(data binding.String) { val, err := data.Get() if err != nil { convertErr = err - e.SetValidationError(err) + e.SetValidationError(e.Validate()) return } e.Text = val @@ -145,7 +146,7 @@ func (e *Entry) Bind(data binding.String) { e.OnChanged = func(s string) { convertErr = data.Set(s) - e.SetValidationError(convertErr) + e.SetValidationError(e.Validate()) } } @@ -161,10 +162,20 @@ func (e *Entry) CreateRenderer() fyne.WidgetRenderer { box := canvas.NewRectangle(theme.InputBackgroundColor()) line := canvas.NewRectangle(theme.ShadowColor()) + cursor := canvas.NewRectangle(color.Transparent) + cursor.Hide() + e.cursorAnim = newEntryCursorAnimation(cursor) e.content = &entryContent{entry: e} - e.scroll = widget.NewScroll(e.content) - objects := []fyne.CanvasObject{box, line, e.scroll} + e.scroll = &widget.Scroll{} + objects := []fyne.CanvasObject{box, line} + if e.Wrapping != fyne.TextWrapOff { + e.scroll.Content = e.content + objects = append(objects, e.scroll) + } else { + e.scroll.Hide() + objects = append(objects, e.content) + } e.content.scroll = e.scroll if e.Password && e.ActionItem == nil { @@ -226,10 +237,19 @@ func (e *Entry) DoubleTapped(p *fyne.PointEvent) { }) } -// DragEnd is called at end of a drag event. It does nothing. +// DragEnd is called at end of a drag event. // // Implements: fyne.Draggable func (e *Entry) DragEnd() { + e.propertyLock.Lock() + if e.CursorColumn == e.selectColumn && e.CursorRow == e.selectRow { + e.selecting = false + } + shouldRefresh := !e.selecting + e.propertyLock.Unlock() + if shouldRefresh { + e.Refresh() + } } // Dragged is called when the pointer moves while a button is held down. @@ -237,12 +257,15 @@ func (e *Entry) DragEnd() { // // Implements: fyne.Draggable func (e *Entry) Dragged(d *fyne.DragEvent) { + pevt := d.PointEvent + // Convert the relative drag position from our Entry coordinates to be relative + // for Scroll.Content + pevt.Position = pevt.Position.Subtract(e.scroll.Offset) if !e.selecting { - e.selectRow, e.selectColumn = e.getRowCol(&d.PointEvent) - + e.selectRow, e.selectColumn = e.getRowCol(&pevt) e.selecting = true } - e.updateMousePointer(&d.PointEvent, false) + e.updateMousePointer(&pevt, false) } // Enable this widget, updating any style or features appropriately. @@ -269,9 +292,6 @@ func (e *Entry) ExtendBaseWidget(wid fyne.Widget) { // // Implements: fyne.Focusable func (e *Entry) FocusGained() { - if e.Disabled() { - return - } e.setFieldsAndRefresh(func() { e.focused = true }) @@ -283,6 +303,7 @@ func (e *Entry) FocusGained() { func (e *Entry) FocusLost() { e.setFieldsAndRefresh(func() { e.focused = false + e.selectKeyDown = false }) } @@ -315,6 +336,9 @@ func (e *Entry) Keyboard() mobile.KeyboardType { // // Implements: desktop.Keyable func (e *Entry) KeyDown(key *fyne.KeyEvent) { + if e.Disabled() { + return + } // For keyboard cursor controlled selection we now need to store shift key state and selection "start" // Note: selection start is where the highlight started (if the user moves the selection up or left then // the selectRow/Column will not match SelectionStart) @@ -331,6 +355,9 @@ func (e *Entry) KeyDown(key *fyne.KeyEvent) { // // Implements: desktop.Keyable func (e *Entry) KeyUp(key *fyne.KeyEvent) { + if e.Disabled() { + return + } // Handle shift release for keyboard selection // Note: if shift is released then the user may repress it without moving to adjust their old selection if key.Name == desktop.KeyShiftLeft || key.Name == desktop.KeyShiftRight { @@ -494,7 +521,9 @@ func (e *Entry) TypedKey(key *fyne.KeyEvent) { if e.Disabled() { return } - + if e.cursorAnim != nil { + e.cursorAnim.interrupt() + } e.propertyLock.RLock() provider := e.textProvider() onSubmitted := e.OnSubmitted @@ -721,9 +750,10 @@ func (e *Entry) copyToClipboard(clipboard fyne.Clipboard) { func (e *Entry) cursorColAt(text []rune, pos fyne.Position) int { for i := 0; i < len(text); i++ { - str := string(text[0 : i+1]) - wid := fyne.MeasureText(str, theme.TextSize(), e.textStyle()).Width + theme.Padding() - if wid > pos.X+theme.Padding() { + str := string(text[0:i]) + wid := fyne.MeasureText(str, theme.TextSize(), e.textStyle()).Width + charWid := fyne.MeasureText(string(text[i]), theme.TextSize(), e.textStyle()).Width + if pos.X < theme.Padding()*2+wid+(charWid/2) { return i } } @@ -804,21 +834,10 @@ func (e *Entry) pasteFromClipboard(clipboard fyne.Clipboard) { } provider := e.textProvider() runes := []rune(text) - provider.insertAt(e.cursorTextPos(), runes) + pos := e.cursorTextPos() + provider.insertAt(pos, runes) + e.CursorRow, e.CursorColumn = e.rowColFromTextPos(pos + len(runes)) - newlines := strings.Count(text, "\n") - if newlines == 0 { - e.CursorColumn += len(runes) - } else { - e.CursorRow += newlines - lastNewlineIndex := 0 - for i, r := range runes { - if r == '\n' { - lastNewlineIndex = i - } - } - e.CursorColumn = len(runes) - lastNewlineIndex - 1 - } e.updateText(provider.String()) e.Refresh() } @@ -859,14 +878,15 @@ func (e *Entry) registerShortcut() { func (e *Entry) rowColFromTextPos(pos int) (row int, col int) { provider := e.textProvider() canWrap := e.Wrapping == fyne.TextWrapBreak || e.Wrapping == fyne.TextWrapWord - for i := 0; i < provider.rows(); i++ { + totalRows := provider.rows() + for i := 0; i < totalRows; i++ { b := provider.rowBoundary(i) if b[0] <= pos { if b[1] < pos { row++ } col = pos - b[0] - if canWrap && b[0] == pos && col == 0 && pos != 0 { + if canWrap && b[0] == pos && col == 0 && pos != 0 && row < (totalRows-1) { row++ } } else { @@ -1080,6 +1100,24 @@ type entryRenderer struct { func (r *entryRenderer) Destroy() { } +func (r *entryRenderer) trailingInset() float32 { + xInset := float32(0) + + if r.entry.ActionItem != nil { + xInset = theme.IconInlineSize() + 2*theme.Padding() + } + + if r.entry.Validator != nil { + if r.entry.ActionItem == nil { + xInset = theme.IconInlineSize() + 2*theme.Padding() + } else { + xInset += theme.IconInlineSize() + theme.Padding() + } + } + + return xInset +} + func (r *entryRenderer) Layout(size fyne.Size) { r.line.Resize(fyne.NewSize(size.Width, theme.InputBorderSize())) r.line.Move(fyne.NewPos(0, size.Height-theme.InputBorderSize())) @@ -1087,10 +1125,8 @@ func (r *entryRenderer) Layout(size fyne.Size) { r.box.Move(fyne.NewPos(0, theme.InputBorderSize())) actionIconSize := fyne.NewSize(0, 0) - xInset := float32(0) if r.entry.ActionItem != nil { actionIconSize = fyne.NewSize(theme.IconInlineSize(), theme.IconInlineSize()) - xInset = theme.IconInlineSize() + 2*theme.Padding() r.entry.ActionItem.Resize(actionIconSize) r.entry.ActionItem.Move(fyne.NewPos(size.Width-actionIconSize.Width-2*theme.Padding(), theme.Padding()*2)) @@ -1105,17 +1141,20 @@ func (r *entryRenderer) Layout(size fyne.Size) { if r.entry.ActionItem == nil { r.entry.validationStatus.Move(fyne.NewPos(size.Width-validatorIconSize.Width-2*theme.Padding(), theme.Padding()*2)) - xInset = theme.IconInlineSize() + 2*theme.Padding() } else { r.entry.validationStatus.Move(fyne.NewPos(size.Width-validatorIconSize.Width-actionIconSize.Width-3*theme.Padding(), theme.Padding()*2)) - xInset += theme.IconInlineSize() + theme.Padding() } } - entrySize := size.Subtract(fyne.NewSize(xInset, theme.InputBorderSize()*2)) + entrySize := size.Subtract(fyne.NewSize(r.trailingInset(), theme.InputBorderSize()*2)) entryPos := fyne.NewPos(0, theme.InputBorderSize()) - r.scroll.Resize(entrySize) - r.scroll.Move(entryPos) + if r.entry.Wrapping == fyne.TextWrapOff { + r.entry.content.Resize(entrySize) + r.entry.content.Move(entryPos) + } else { + r.scroll.Resize(entrySize) + r.scroll.Move(entryPos) + } } // MinSize calculates the minimum size of an entry widget. @@ -1123,7 +1162,7 @@ func (r *entryRenderer) Layout(size fyne.Size) { // If MultiLine is true then we will reserve space for at leasts 3 lines func (r *entryRenderer) MinSize() fyne.Size { if r.scroll.Direction == widget.ScrollNone { - return r.scroll.MinSize().Add(fyne.NewSize(0, theme.InputBorderSize()*2)) + return r.entry.content.MinSize().Add(fyne.NewSize(0, theme.InputBorderSize()*2)) } minSize := r.entry.placeholderProvider().charMinSize().Add(fyne.NewSize(theme.Padding()*2, theme.Padding()*2)) @@ -1147,17 +1186,49 @@ func (r *entryRenderer) Objects() []fyne.CanvasObject { func (r *entryRenderer) Refresh() { r.entry.propertyLock.RLock() provider := r.entry.textProvider() - content := r.entry.Text - focused := r.entry.focused + text := r.entry.Text + content := r.entry.content + focusedAppearance := r.entry.focused && !r.entry.disabled + size := r.entry.size + wrapping := r.entry.Wrapping r.entry.propertyLock.RUnlock() - if content != string(provider.buffer) { - r.entry.SetText(content) + // correct our scroll wrappers if the wrap mode changed + entrySize := size.Subtract(fyne.NewSize(r.trailingInset(), theme.InputBorderSize()*2)) + if wrapping == fyne.TextWrapOff && r.scroll.Content != nil { + r.scroll.Hide() + r.scroll.Content = nil + content.Move(fyne.NewPos(0, theme.InputBorderSize())) + content.Resize(entrySize) + + for i, o := range r.objects { + if o == r.scroll { + r.objects[i] = content + break + } + } + } else if wrapping != fyne.TextWrapOff && r.scroll.Content == nil { + r.scroll.Content = content + content.Move(fyne.NewPos(0, 0)) + r.scroll.Move(fyne.NewPos(0, theme.InputBorderSize())) + r.scroll.Resize(entrySize) + r.scroll.Show() + + for i, o := range r.objects { + if o == content { + r.objects[i] = r.scroll + break + } + } + } + + if text != string(provider.buffer) { + r.entry.SetText(text) return } r.box.FillColor = theme.InputBackgroundColor() - if focused { + if focusedAppearance { r.line.FillColor = theme.PrimaryColor() } else { if r.entry.Disabled() { @@ -1181,7 +1252,7 @@ func (r *entryRenderer) Refresh() { } if r.entry.Validator != nil { - if !r.entry.focused && r.entry.Text != "" && r.entry.validationError != nil { + if !r.entry.focused && !r.entry.Disabled() && r.entry.Text != "" && r.entry.validationError != nil { r.line.FillColor = theme.ErrorColor() } r.ensureValidationSetup() @@ -1190,7 +1261,7 @@ func (r *entryRenderer) Refresh() { r.entry.validationStatus.Hide() } - cache.Renderer(r.scroll.Content.(*entryContent)).Refresh() + cache.Renderer(r.entry.content).Refresh() canvas.Refresh(r.entry.super()) } @@ -1199,6 +1270,10 @@ func (r *entryRenderer) ensureValidationSetup() { r.entry.validationStatus = newValidationStatus(r.entry) r.objects = append(r.objects, r.entry.validationStatus) r.Layout(r.entry.size) + + if r.entry.Text != "" { + r.entry.Validate() + } r.Refresh() } } @@ -1215,9 +1290,6 @@ type entryContent struct { func (e *entryContent) CreateRenderer() fyne.WidgetRenderer { e.ExtendBaseWidget(e) - cursor := canvas.NewRectangle(color.Transparent) - cursor.Hide() - e.entry.propertyLock.Lock() defer e.entry.propertyLock.Unlock() provider := e.entry.textProvider() @@ -1225,16 +1297,16 @@ func (e *entryContent) CreateRenderer() fyne.WidgetRenderer { if provider.len() != 0 { placeholder.Hide() } - objects := []fyne.CanvasObject{placeholder, provider, cursor} + objects := []fyne.CanvasObject{placeholder, provider, e.entry.cursorAnim.cursor} - r := &entryContentRenderer{cursor, []fyne.CanvasObject{}, nil, objects, + r := &entryContentRenderer{e.entry.cursorAnim.cursor, []fyne.CanvasObject{}, objects, provider, placeholder, e} r.updateScrollDirections() r.Layout(e.size) return r } -// DragEnd is called at end of a drag event. It does nothing. +// DragEnd is called at end of a drag event. // // Implements: fyne.Draggable func (e *entryContent) DragEnd() { @@ -1256,17 +1328,16 @@ func (e *entryContent) Dragged(d *fyne.DragEvent) { var _ fyne.WidgetRenderer = (*entryContentRenderer)(nil) type entryContentRenderer struct { - cursor *canvas.Rectangle - selection []fyne.CanvasObject - cursorAnim *fyne.Animation - objects []fyne.CanvasObject + cursor *canvas.Rectangle + selection []fyne.CanvasObject + objects []fyne.CanvasObject provider, placeholder *textProvider content *entryContent } func (r *entryContentRenderer) Destroy() { - r.cursorAnim.Stop() + r.content.entry.cursorAnim.stop() } func (r *entryContentRenderer) Layout(size fyne.Size) { @@ -1289,7 +1360,9 @@ func (r *entryContentRenderer) Objects() []fyne.CanvasObject { defer r.content.entry.propertyLock.RUnlock() // Objects are generated dynamically force selection rectangles to appear underneath the text if r.content.entry.selecting { - return append(r.selection, r.objects...) + objs := make([]fyne.CanvasObject, 0, len(r.selection)+len(r.objects)) + objs = append(objs, r.selection...) + return append(objs, r.objects...) } return r.objects } @@ -1299,7 +1372,7 @@ func (r *entryContentRenderer) Refresh() { provider := r.content.entry.textProvider() placeholder := r.content.entry.placeholderProvider() content := r.content.entry.Text - focused := r.content.entry.focused + focusedAppearance := r.content.entry.focused && !r.content.entry.disabled selections := r.selection r.updateScrollDirections() r.content.entry.propertyLock.RUnlock() @@ -1314,23 +1387,17 @@ func (r *entryContentRenderer) Refresh() { placeholder.Hide() } - if focused { + if focusedAppearance { r.cursor.Show() - if r.cursorAnim == nil { - r.cursorAnim = makeCursorAnimation(r.cursor) - r.cursorAnim.Start() - } + r.content.entry.cursorAnim.start() } else { - if r.cursorAnim != nil { - r.cursorAnim.Stop() - r.cursorAnim = nil - } + r.content.entry.cursorAnim.stop() r.cursor.Hide() } r.moveCursor() for _, selection := range selections { - selection.(*canvas.Rectangle).Hidden = !r.content.entry.focused && !r.content.entry.disabled + selection.(*canvas.Rectangle).Hidden = !r.content.entry.focused selection.(*canvas.Rectangle).FillColor = theme.PrimaryColor() } @@ -1354,7 +1421,7 @@ func (r *entryContentRenderer) buildSelection() { } r.content.entry.propertyLock.RUnlock() - if selectRow == -1 { + if selectRow == -1 || (cursorRow == selectRow && cursorCol == selectCol) { r.selection = r.selection[:0] return @@ -1446,8 +1513,10 @@ func (r *entryContentRenderer) ensureCursorVisible() { } else if cy2 >= offset.X+size.Height { move.DY += cy2 - (offset.Y + size.Height) } - r.content.scroll.Offset = r.content.scroll.Offset.Add(move) - r.content.scroll.Refresh() + if r.content.scroll.Content != nil { + r.content.scroll.Offset = r.content.scroll.Offset.Add(move) + r.content.scroll.Refresh() + } } func (r *entryContentRenderer) moveCursor() { @@ -1572,17 +1641,3 @@ func getTextWhitespaceRegion(row []rune, col int) (int, int) { } return start, end } - -func makeCursorAnimation(cursor *canvas.Rectangle) *fyne.Animation { - cursorOpaque := theme.PrimaryColor() - r, g, b, _ := theme.PrimaryColor().RGBA() - cursorDim := color.NRGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 0x16} - anim := canvas.NewColorRGBAAnimation(cursorDim, cursorOpaque, time.Second/2, func(c color.Color) { - cursor.FillColor = c - cursor.Refresh() - }) - anim.RepeatCount = fyne.AnimationRepeatForever - anim.AutoReverse = true - - return anim -} diff --git a/vendor/fyne.io/fyne/v2/widget/entry_cursor_anim.go b/vendor/fyne.io/fyne/v2/widget/entry_cursor_anim.go new file mode 100644 index 0000000..5fcfc83 --- /dev/null +++ b/vendor/fyne.io/fyne/v2/widget/entry_cursor_anim.go @@ -0,0 +1,106 @@ +package widget + +import ( + "image/color" + "sync" + "time" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/theme" +) + +const cursorInterruptTime = 300 * time.Millisecond + +type entryCursorAnimation struct { + mu *sync.RWMutex + cursor *canvas.Rectangle + anim *fyne.Animation + lastInterruptTime time.Time + + timeNow func() time.Time // useful for testing +} + +func newEntryCursorAnimation(cursor *canvas.Rectangle) *entryCursorAnimation { + a := &entryCursorAnimation{mu: &sync.RWMutex{}, cursor: cursor, timeNow: time.Now} + return a +} + +// creates fyne animation +func (a *entryCursorAnimation) createAnim(inverted bool) *fyne.Animation { + cursorOpaque := theme.PrimaryColor() + r, g, b, _ := theme.PrimaryColor().RGBA() + cursorDim := color.NRGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 0x16} + start, end := color.Color(cursorDim), color.Color(cursorOpaque) + if inverted { + start, end = color.Color(cursorOpaque), color.Color(cursorDim) + } + interrupted := false + anim := canvas.NewColorRGBAAnimation(start, end, time.Second/2, func(c color.Color) { + a.mu.RLock() + shouldInterrupt := a.timeNow().Sub(a.lastInterruptTime) <= cursorInterruptTime + a.mu.RUnlock() + if shouldInterrupt { + if !interrupted { + a.cursor.FillColor = cursorOpaque + a.cursor.Refresh() + interrupted = true + } + return + } + if interrupted { + a.mu.Lock() + a.anim.Stop() + if !inverted { + a.anim = a.createAnim(true) + } + interrupted = false + a.mu.Unlock() + go func() { + a.mu.RLock() + canStart := a.anim != nil + a.mu.RUnlock() + if canStart { + a.anim.Start() + } + }() + return + } + a.cursor.FillColor = c + a.cursor.Refresh() + }) + + anim.RepeatCount = fyne.AnimationRepeatForever + anim.AutoReverse = true + return anim +} + +// starts cursor animation. +func (a *entryCursorAnimation) start() { + a.mu.Lock() + isStopped := a.anim == nil + if isStopped { + a.anim = a.createAnim(false) + } + a.mu.Unlock() + if isStopped { + a.anim.Start() + } +} + +// temporarily stops the animation by "cursorInterruptTime". +func (a *entryCursorAnimation) interrupt() { + a.mu.Lock() + a.lastInterruptTime = a.timeNow() + a.mu.Unlock() +} + +// stops cursor animation. +func (a *entryCursorAnimation) stop() { + a.mu.Lock() + if a.anim != nil { + a.anim.Stop() + a.anim = nil + } + a.mu.Unlock() +} diff --git a/vendor/fyne.io/fyne/v2/widget/entry_password.go b/vendor/fyne.io/fyne/v2/widget/entry_password.go index 6b73f8a..acf80a5 100644 --- a/vendor/fyne.io/fyne/v2/widget/entry_password.go +++ b/vendor/fyne.io/fyne/v2/widget/entry_password.go @@ -46,7 +46,7 @@ func (r *passwordRevealer) Tapped(*fyne.PointEvent) { r.entry.setFieldsAndRefresh(func() { r.entry.Password = !r.entry.Password }) - fyne.CurrentApp().Driver().CanvasForObject(r).Focus(r.entry) + fyne.CurrentApp().Driver().CanvasForObject(r).Focus(r.entry.super().(fyne.Focusable)) } var _ fyne.WidgetRenderer = (*passwordRevealerRenderer)(nil) diff --git a/vendor/fyne.io/fyne/v2/widget/entry_validation.go b/vendor/fyne.io/fyne/v2/widget/entry_validation.go index 5a380f6..5a162ea 100644 --- a/vendor/fyne.io/fyne/v2/widget/entry_validation.go +++ b/vendor/fyne.io/fyne/v2/widget/entry_validation.go @@ -95,7 +95,7 @@ func (r *validationStatusRenderer) MinSize() fyne.Size { func (r *validationStatusRenderer) Refresh() { r.entry.propertyLock.RLock() defer r.entry.propertyLock.RUnlock() - if r.entry.Text == "" { + if r.entry.Text == "" || r.entry.disabled { r.icon.Hide() return } diff --git a/vendor/fyne.io/fyne/v2/widget/fileicon.go b/vendor/fyne.io/fyne/v2/widget/fileicon.go index b2c10df..fd6cfef 100644 --- a/vendor/fyne.io/fyne/v2/widget/fileicon.go +++ b/vendor/fyne.io/fyne/v2/widget/fileicon.go @@ -67,18 +67,25 @@ func (i *FileIcon) MinSize() fyne.Size { // CreateRenderer is a private method to Fyne which links this widget to its renderer func (i *FileIcon) CreateRenderer() fyne.WidgetRenderer { i.ExtendBaseWidget(i) + i.propertyLock.Lock() + i.setURI(i.URI) + i.propertyLock.Unlock() + i.propertyLock.RLock() defer i.propertyLock.RUnlock() - i.setURI(i.URI) - // TODO should FileIcon render a background representing selection, or should it be in the collection? // TODO file dialog currently uses a container with NewGridWrapLayout, but if this changes to List, or Table then the primary color background would be rendered twice. background := canvas.NewRectangle(theme.PrimaryColor()) background.Hide() s := &fileIconRenderer{file: i, background: background} - s.updateObjects() + s.img = canvas.NewImageFromResource(s.file.resource) + s.img.FillMode = canvas.ImageFillContain + s.ext = canvas.NewText(s.file.extension, theme.BackgroundColor()) + s.ext.Alignment = fyne.TextAlignCenter + + s.SetObjects([]fyne.CanvasObject{s.background, s.img, s.ext}) i.cachedURI = i.URI return s @@ -149,9 +156,13 @@ func (s *fileIconRenderer) Layout(size fyne.Size) { } yoff += isize * ratioDown + oldSize := s.ext.TextSize s.ext.TextSize = float32(int(isize * ratioTextSize)) s.ext.Resize(fyne.NewSize(isize, s.ext.MinSize().Height)) s.ext.Move(fyne.NewPos(xoff, yoff)) + if oldSize != s.ext.TextSize { + s.ext.Refresh() + } s.Objects()[0].Resize(size) s.Objects()[1].Resize(size) @@ -159,10 +170,14 @@ func (s *fileIconRenderer) Layout(size fyne.Size) { func (s *fileIconRenderer) Refresh() { if s.file.URI != s.file.cachedURI { - s.file.propertyLock.RLock() + s.file.propertyLock.Lock() s.file.setURI(s.file.URI) - s.updateObjects() + s.file.propertyLock.Unlock() + + s.file.propertyLock.RLock() s.file.cachedURI = s.file.URI + s.img.Resource = s.file.resource + s.ext.Text = s.file.extension s.file.propertyLock.RUnlock() } @@ -184,16 +199,6 @@ func (s *fileIconRenderer) Refresh() { canvas.Refresh(s.ext) } -func (s *fileIconRenderer) updateObjects() { - s.img = canvas.NewImageFromResource(s.file.resource) - s.ext = canvas.NewText(s.file.extension, theme.BackgroundColor()) - s.img.FillMode = canvas.ImageFillContain - s.ext.Alignment = fyne.TextAlignCenter - s.ext.TextSize = theme.TextSize() - - s.SetObjects([]fyne.CanvasObject{s.background, s.img, s.ext}) -} - func trimmedExtension(uri fyne.URI) string { ext := uri.Extension() if len(ext) > 5 { diff --git a/vendor/fyne.io/fyne/v2/widget/form.go b/vendor/fyne.io/fyne/v2/widget/form.go index c75fd82..c6b6966 100644 --- a/vendor/fyne.io/fyne/v2/widget/form.go +++ b/vendor/fyne.io/fyne/v2/widget/form.go @@ -1,6 +1,8 @@ package widget import ( + "errors" + "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/internal/cache" @@ -8,6 +10,10 @@ import ( "fyne.io/fyne/v2/theme" ) +// errFormItemInitialState defines the error if the initial validation for a FormItem result +// in an error +var errFormItemInitialState = errors.New("widget.FormItem initial state error") + // FormItem provides the details for a row in a form type FormItem struct { Text string @@ -155,10 +161,14 @@ func (f *Form) checkValidation(err error) { func (f *Form) setUpValidation(widget fyne.CanvasObject, i int) { if w, ok := widget.(fyne.Validatable); ok { f.Items[i].invalid = w.Validate() != nil - if e, ok := w.(*Entry); ok && e.Validator != nil { - e.SetValidationError(nil) // clear initial state, will appear when we type + if e, ok := w.(*Entry); ok && e.Validator != nil && f.Items[i].invalid { + // set initial state error to guarantee next error (if triggers) is always different + e.SetValidationError(errFormItemInitialState) } w.SetOnValidationChanged(func(err error) { + if err == errFormItemInitialState { + return + } f.Items[i].validationError = err f.Items[i].invalid = err != nil f.checkValidation(err) diff --git a/vendor/fyne.io/fyne/v2/widget/hyperlink.go b/vendor/fyne.io/fyne/v2/widget/hyperlink.go index d40f00f..9863d5a 100644 --- a/vendor/fyne.io/fyne/v2/widget/hyperlink.go +++ b/vendor/fyne.io/fyne/v2/widget/hyperlink.go @@ -121,7 +121,7 @@ func (hl *Hyperlink) Tapped(*fyne.PointEvent) { func (hl *Hyperlink) CreateRenderer() fyne.WidgetRenderer { hl.ExtendBaseWidget(hl) hl.provider = newTextProvider(hl.Text, hl) - hl.provider.extraPad = fyne.NewSize(0, theme.Padding()) + hl.provider.extraPad = fyne.NewSize(theme.Padding(), theme.Padding()) return hl.provider.CreateRenderer() } diff --git a/vendor/fyne.io/fyne/v2/widget/label.go b/vendor/fyne.io/fyne/v2/widget/label.go index f96058d..ccc6ada 100644 --- a/vendor/fyne.io/fyne/v2/widget/label.go +++ b/vendor/fyne.io/fyne/v2/widget/label.go @@ -152,7 +152,7 @@ func (l *Label) object() fyne.Widget { func (l *Label) CreateRenderer() fyne.WidgetRenderer { l.ExtendBaseWidget(l) l.provider = newTextProvider(l.Text, l) - l.provider.extraPad = fyne.NewSize(0, theme.Padding()) + l.provider.extraPad = fyne.NewSize(theme.Padding(), theme.Padding()) l.provider.size = l.size return l.provider.CreateRenderer() } diff --git a/vendor/fyne.io/fyne/v2/widget/list.go b/vendor/fyne.io/fyne/v2/widget/list.go index cc0be32..f5f933d 100644 --- a/vendor/fyne.io/fyne/v2/widget/list.go +++ b/vendor/fyne.io/fyne/v2/widget/list.go @@ -3,6 +3,7 @@ package widget import ( "fmt" "math" + "sync" "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" @@ -78,12 +79,12 @@ func (l *List) CreateRenderer() fyne.WidgetRenderer { l.itemMin = newListItem(f(), nil).MinSize() } } - layout := fyne.NewContainerWithLayout(newListLayout(l)) - layout.Resize(layout.MinSize()) + layout := &fyne.Container{} l.scroller = widget.NewVScroll(layout) + layout.Layout = newListLayout(l) + layout.Resize(layout.MinSize()) objects := []fyne.CanvasObject{l.scroller} lr := newListRenderer(objects, l, l.scroller, layout) - l.offsetUpdated = lr.offsetUpdated return lr } @@ -148,87 +149,19 @@ var _ fyne.WidgetRenderer = (*listRenderer)(nil) type listRenderer struct { widget.BaseRenderer - list *List - scroller *widget.Scroll - layout *fyne.Container - itemPool *syncPool - children []fyne.CanvasObject - size fyne.Size - visibleItemCount int - firstItemIndex ListItemID - lastItemIndex ListItemID - previousOffsetY float32 + list *List + scroller *widget.Scroll + layout *fyne.Container } func newListRenderer(objects []fyne.CanvasObject, l *List, scroller *widget.Scroll, layout *fyne.Container) *listRenderer { lr := &listRenderer{BaseRenderer: widget.NewBaseRenderer(objects), list: l, scroller: scroller, layout: layout} - lr.scroller.OnScrolled = lr.offsetUpdated + lr.scroller.OnScrolled = l.offsetUpdated return lr } func (l *listRenderer) Layout(size fyne.Size) { - length := 0 - if f := l.list.Length; f != nil { - length = f() - } - if length <= 0 { - if len(l.children) > 0 { - for _, child := range l.children { - l.itemPool.Release(child) - } - l.previousOffsetY = 0 - l.firstItemIndex = 0 - l.lastItemIndex = 0 - l.visibleItemCount = 0 - l.list.offsetY = 0 - l.layout.Layout.(*listLayout).layoutEndY = 0 - l.children = nil - l.layout.Objects = nil - l.list.Refresh() - } - return - } - if size != l.size { - if size.Width != l.size.Width { - for _, child := range l.children { - child.Resize(fyne.NewSize(size.Width, l.list.itemMin.Height)) - } - } - l.scroller.Resize(size) - l.size = size - } - if l.itemPool == nil { - l.itemPool = &syncPool{} - } - - // Relayout What Is Visible - no scroll change - initial layout or possibly from a resize. - l.visibleItemCount = int(math.Ceil(float64(l.scroller.Size().Height) / float64(l.list.itemMin.Height+theme.SeparatorThicknessSize()))) - if l.visibleItemCount <= 0 { - return - } - min := int(fyne.Min(float32(length), float32(l.visibleItemCount))) - if len(l.children) > min { - for i := len(l.children); i >= min; i-- { - l.itemPool.Release(l.children[i-1]) - } - l.children = l.children[:min-1] - } - for i := len(l.children) + l.firstItemIndex; len(l.children) <= l.visibleItemCount && i < length; i++ { - l.appendItem(i) - } - l.layout.Layout.(*listLayout).children = l.children - l.layout.Layout.Layout(l.children, l.list.itemMin) - l.layout.Objects = l.layout.Layout.(*listLayout).getObjects() - l.lastItemIndex = l.firstItemIndex + len(l.children) - 1 - - i := l.firstItemIndex - for _, child := range l.children { - if f := l.list.UpdateItem; f != nil { - f(i, child.(*listItem).child) - } - l.setupListItem(child, i) - i++ - } + l.scroller.Resize(size) } func (l *listRenderer) MinSize() fyne.Size { @@ -244,125 +177,6 @@ func (l *listRenderer) Refresh() { canvas.Refresh(l.list.super()) } -func (l *listRenderer) appendItem(id ListItemID) { - item := l.getItem() - l.children = append(l.children, item) - l.setupListItem(item, id) - l.layout.Layout.(*listLayout).children = l.children - l.layout.Layout.(*listLayout).appendedItem(l.children) - l.layout.Objects = l.layout.Layout.(*listLayout).getObjects() -} - -func (l *listRenderer) getItem() fyne.CanvasObject { - item := l.itemPool.Obtain() - if item == nil { - if f := l.list.CreateItem; f != nil { - item = newListItem(f(), nil) - } - } - return item -} - -func (l *listRenderer) offsetChanged() { - offsetChange := float32(math.Abs(float64(l.previousOffsetY - l.list.offsetY))) - - if l.previousOffsetY < l.list.offsetY { - // Scrolling Down. - l.scrollDown(offsetChange) - } else if l.previousOffsetY > l.list.offsetY { - // Scrolling Up. - l.scrollUp(offsetChange) - } - l.layout.Layout.(*listLayout).updateDividers() -} - -func (l *listRenderer) prependItem(id ListItemID) { - item := l.getItem() - l.children = append([]fyne.CanvasObject{item}, l.children...) - l.setupListItem(item, id) - l.layout.Layout.(*listLayout).children = l.children - l.layout.Layout.(*listLayout).prependedItem(l.children) - l.layout.Objects = l.layout.Layout.(*listLayout).getObjects() -} - -func (l *listRenderer) scrollDown(offsetChange float32) { - itemChange := 0 - separatorThickness := theme.SeparatorThicknessSize() - layoutEndY := l.children[len(l.children)-1].Position().Y + l.list.itemMin.Height + separatorThickness - scrollerEndY := l.scroller.Offset.Y + l.scroller.Size().Height - if layoutEndY < scrollerEndY { - itemChange = int(math.Ceil(float64(scrollerEndY-layoutEndY) / float64(l.list.itemMin.Height+separatorThickness))) - } else if offsetChange < l.list.itemMin.Height+separatorThickness { - return - } else { - itemChange = int(math.Floor(float64(offsetChange) / float64(l.list.itemMin.Height+separatorThickness))) - } - l.previousOffsetY = l.list.offsetY - length := 0 - if f := l.list.Length; f != nil { - length = f() - } - if length == 0 { - return - } - for i := 0; i < itemChange && l.lastItemIndex != length-1; i++ { - l.itemPool.Release(l.children[0]) - l.children = l.children[1:] - l.firstItemIndex++ - l.lastItemIndex++ - l.appendItem(l.lastItemIndex) - } -} - -func (l *listRenderer) scrollUp(offsetChange float32) { - itemChange := 0 - layoutStartY := l.children[0].Position().Y - separatorThickness := theme.SeparatorThicknessSize() - if layoutStartY > l.scroller.Offset.Y { - itemChange = int(math.Ceil(float64(layoutStartY-l.scroller.Offset.Y) / float64(l.list.itemMin.Height+separatorThickness))) - } else if offsetChange < l.list.itemMin.Height+separatorThickness { - return - } else { - itemChange = int(math.Floor(float64(offsetChange) / float64(l.list.itemMin.Height+separatorThickness))) - } - l.previousOffsetY = l.list.offsetY - for i := 0; i < itemChange && l.firstItemIndex != 0; i++ { - l.itemPool.Release(l.children[len(l.children)-1]) - l.children = l.children[:len(l.children)-1] - l.firstItemIndex-- - l.lastItemIndex-- - l.prependItem(l.firstItemIndex) - } -} - -func (l *listRenderer) setupListItem(item fyne.CanvasObject, id ListItemID) { - li := item.(*listItem) - previousIndicator := li.selected - li.selected = false - for _, s := range l.list.selected { - if id == s { - li.selected = true - } - } - if previousIndicator != li.selected { - item.Refresh() - } - if f := l.list.UpdateItem; f != nil { - f(id, li.child) - } - li.onTapped = func() { - l.list.Select(id) - } -} - -func (l *listRenderer) offsetUpdated(pos fyne.Position) { - if l.list.offsetY == pos.Y { - return - } - l.list.offsetY = pos.Y - l.offsetChanged() -} - // Declare conformity with interfaces. var _ fyne.Widget = (*listItem)(nil) var _ fyne.Tappable = (*listItem)(nil) @@ -477,31 +291,26 @@ func (li *listItemRenderer) Refresh() { var _ fyne.Layout = (*listLayout)(nil) type listLayout struct { - list *List - dividers []fyne.CanvasObject - children []fyne.CanvasObject - layoutEndY float32 + list *List + dividers []fyne.CanvasObject + children []fyne.CanvasObject + + itemPool *syncPool + visible map[ListItemID]*listItem + renderLock sync.Mutex } func newListLayout(list *List) fyne.Layout { - return &listLayout{list: list} + l := &listLayout{list: list, itemPool: &syncPool{}, visible: make(map[ListItemID]*listItem)} + list.offsetUpdated = l.offsetUpdated + return l } -func (l *listLayout) Layout(objects []fyne.CanvasObject, size fyne.Size) { - if l.list.offsetY != 0 { - return - } - y := float32(0) - for _, child := range l.children { - child.Move(fyne.NewPos(0, y)) - y += l.list.itemMin.Height + theme.SeparatorThicknessSize() - child.Resize(fyne.NewSize(l.list.size.Width, l.list.itemMin.Height)) - } - l.layoutEndY = y - l.updateDividers() +func (l *listLayout) Layout([]fyne.CanvasObject, fyne.Size) { + l.updateList() } -func (l *listLayout) MinSize(objects []fyne.CanvasObject) fyne.Size { +func (l *listLayout) MinSize([]fyne.CanvasObject) fyne.Size { if f := l.list.Length; f != nil { separatorThickness := theme.SeparatorThicknessSize() return fyne.NewSize(l.list.itemMin.Width, @@ -510,24 +319,96 @@ func (l *listLayout) MinSize(objects []fyne.CanvasObject) fyne.Size { return fyne.NewSize(0, 0) } -func (l *listLayout) getObjects() []fyne.CanvasObject { - objects := l.children - objects = append(objects, l.dividers...) - return objects +func (l *listLayout) getItem() *listItem { + item := l.itemPool.Obtain() + if item == nil { + if f := l.list.CreateItem; f != nil { + item = newListItem(f(), nil) + } + } + return item.(*listItem) } -func (l *listLayout) appendedItem(objects []fyne.CanvasObject) { - if len(objects) > 1 { - objects[len(objects)-1].Move(fyne.NewPos(0, objects[len(objects)-2].Position().Y+l.list.itemMin.Height+theme.SeparatorThicknessSize())) - } else { - objects[len(objects)-1].Move(fyne.NewPos(0, 0)) +func (l *listLayout) offsetUpdated(pos fyne.Position) { + if l.list.offsetY == pos.Y { + return } - objects[len(objects)-1].Resize(fyne.NewSize(l.list.size.Width, l.list.itemMin.Height)) + l.list.offsetY = pos.Y + l.updateList() } -func (l *listLayout) prependedItem(objects []fyne.CanvasObject) { - objects[0].Move(fyne.NewPos(0, objects[1].Position().Y-l.list.itemMin.Height-theme.SeparatorThicknessSize())) - objects[0].Resize(fyne.NewSize(l.list.size.Width, l.list.itemMin.Height)) +func (l *listLayout) setupListItem(li *listItem, id ListItemID) { + previousIndicator := li.selected + li.selected = false + for _, s := range l.list.selected { + if id == s { + li.selected = true + break + } + } + if previousIndicator != li.selected { + li.Refresh() + } + if f := l.list.UpdateItem; f != nil { + f(id, li.child) + } + li.onTapped = func() { + l.list.Select(id) + } +} + +func (l *listLayout) updateList() { + l.renderLock.Lock() + defer l.renderLock.Unlock() + separatorThickness := theme.SeparatorThicknessSize() + width := l.list.Size().Width + length := 0 + if f := l.list.Length; f != nil { + length = f() + } + visibleItemCount := int(math.Ceil(float64(l.list.scroller.Size().Height)/float64(l.list.itemMin.Height+theme.SeparatorThicknessSize()))) + 1 + offY := l.list.offsetY - float32(int(l.list.offsetY)%int(l.list.itemMin.Height+separatorThickness)) + minRow := ListItemID(offY / (l.list.itemMin.Height + separatorThickness)) + maxRow := ListItemID(fyne.Min(float32(minRow+visibleItemCount), float32(length))) + + if l.list.UpdateItem == nil { + fyne.LogError("Missing UpdateCell callback required for List", nil) + } + + wasVisible := l.visible + l.visible = make(map[ListItemID]*listItem) + var cells []fyne.CanvasObject + y := offY + size := fyne.NewSize(width, l.list.itemMin.Height) + for row := minRow; row < maxRow; row++ { + c, ok := wasVisible[row] + if !ok { + c = l.getItem() + if c == nil { + continue + } + } + + c.Move(fyne.NewPos(0, y)) + c.Resize(size) + l.setupListItem(c, row) + + y += l.list.itemMin.Height + separatorThickness + l.visible[row] = c + cells = append(cells, c) + } + + for id, old := range wasVisible { + if _, ok := l.visible[id]; !ok { + l.itemPool.Release(old) + } + } + l.children = cells + l.updateDividers() + + objects := l.children + objects = append(objects, l.dividers...) + l.list.scroller.Content.(*fyne.Container).Objects = objects } func (l *listLayout) updateDividers() { diff --git a/vendor/fyne.io/fyne/v2/widget/popup.go b/vendor/fyne.io/fyne/v2/widget/popup.go index 848f33e..652af47 100644 --- a/vendor/fyne.io/fyne/v2/widget/popup.go +++ b/vendor/fyne.io/fyne/v2/widget/popup.go @@ -48,7 +48,6 @@ func (p *PopUp) Move(pos fyne.Position) { // Implements: fyne.Widget func (p *PopUp) Resize(size fyne.Size) { p.innerSize = size - p.BaseWidget.Resize(p.Canvas.Size()) // The canvas size might not have changed and therefore the Resize won't trigger a layout. // Until we have a widget.Relayout() or similar, the renderer's refresh will do the re-layout. p.Refresh() @@ -57,12 +56,10 @@ func (p *PopUp) Resize(size fyne.Size) { // Show this pop-up as overlay if not already shown. func (p *PopUp) Show() { if !p.overlayShown { - if p.Size().IsZero() { - p.Resize(p.MinSize()) - } p.Canvas.Overlays().Add(p) p.overlayShown = true } + p.Refresh() p.BaseWidget.Show() } @@ -172,26 +169,27 @@ type popUpRenderer struct { } func (r *popUpRenderer) Layout(_ fyne.Size) { - r.popUp.Content.Resize(r.popUp.innerSize.Subtract(r.padding())) + innerSize := r.popUp.innerSize.Max(r.popUp.MinSize()) + r.popUp.Content.Resize(innerSize.Subtract(r.padding())) innerPos := r.popUp.innerPos - if innerPos.X+r.popUp.innerSize.Width > r.popUp.Canvas.Size().Width { - innerPos.X = r.popUp.Canvas.Size().Width - r.popUp.innerSize.Width + if innerPos.X+innerSize.Width > r.popUp.Canvas.Size().Width { + innerPos.X = r.popUp.Canvas.Size().Width - innerSize.Width if innerPos.X < 0 { innerPos.X = 0 // TODO here we may need a scroller as it's wider than our canvas } } - if innerPos.Y+r.popUp.innerSize.Height > r.popUp.Canvas.Size().Height { - innerPos.Y = r.popUp.Canvas.Size().Height - r.popUp.innerSize.Height + if innerPos.Y+innerSize.Height > r.popUp.Canvas.Size().Height { + innerPos.Y = r.popUp.Canvas.Size().Height - innerSize.Height if innerPos.Y < 0 { innerPos.Y = 0 // TODO here we may need a scroller as it's longer than our canvas } } r.popUp.Content.Move(innerPos.Add(r.offset())) - r.background.Resize(r.popUp.innerSize) + r.background.Resize(innerSize) r.background.Move(innerPos) - r.LayoutShadow(r.popUp.innerSize, innerPos) + r.LayoutShadow(innerSize, innerPos) } func (r *popUpRenderer) MinSize() fyne.Size { @@ -200,9 +198,16 @@ func (r *popUpRenderer) MinSize() fyne.Size { func (r *popUpRenderer) Refresh() { r.background.FillColor = theme.BackgroundColor() - if r.background.Size() != r.popUp.innerSize || r.background.Position() != r.popUp.innerPos { + expectedContentSize := r.popUp.innerSize.Max(r.popUp.MinSize()).Subtract(r.padding()) + shouldRelayout := !r.popUp.Content.Size().Subtract(expectedContentSize).IsZero() + + if r.background.Size() != r.popUp.innerSize || r.background.Position() != r.popUp.innerPos || shouldRelayout { r.Layout(r.popUp.Size()) } + if !r.popUp.Canvas.Size().Subtract(r.popUp.BaseWidget.Size()).IsZero() { + r.popUp.BaseWidget.Resize(r.popUp.Canvas.Size()) + } + r.popUp.Content.Refresh() r.background.Refresh() } @@ -238,8 +243,15 @@ func (r *modalPopUpRenderer) MinSize() fyne.Size { func (r *modalPopUpRenderer) Refresh() { r.underlay.FillColor = theme.ShadowColor() r.background.FillColor = theme.BackgroundColor() - if r.background.Size() != r.popUp.innerSize { + expectedContentSize := r.popUp.innerSize.Max(r.popUp.MinSize()).Subtract(r.padding()) + shouldRelayout := !r.popUp.Content.Size().Subtract(expectedContentSize).IsZero() + + if r.background.Size() != r.popUp.innerSize || shouldRelayout { r.Layout(r.popUp.Size()) } + if !r.popUp.Canvas.Size().Subtract(r.popUp.BaseWidget.Size()).IsZero() { + r.popUp.BaseWidget.Resize(r.popUp.Canvas.Size()) + } + r.popUp.Content.Refresh() r.background.Refresh() } diff --git a/vendor/fyne.io/fyne/v2/widget/progressbar.go b/vendor/fyne.io/fyne/v2/widget/progressbar.go index 6de273d..80033aa 100644 --- a/vendor/fyne.io/fyne/v2/widget/progressbar.go +++ b/vendor/fyne.io/fyne/v2/widget/progressbar.go @@ -136,7 +136,7 @@ func (p *ProgressBar) CreateRenderer() fyne.WidgetRenderer { p.Max = 1.0 } - background := canvas.NewRectangle(theme.ShadowColor()) + background := canvas.NewRectangle(progressBackgroundColor()) bar := canvas.NewRectangle(theme.PrimaryColor()) label := canvas.NewText("0%", theme.ForegroundColor()) label.Alignment = fyne.TextAlignCenter diff --git a/vendor/fyne.io/fyne/v2/widget/select_entry.go b/vendor/fyne.io/fyne/v2/widget/select_entry.go index c9ad389..92c878f 100644 --- a/vendor/fyne.io/fyne/v2/widget/select_entry.go +++ b/vendor/fyne.io/fyne/v2/widget/select_entry.go @@ -17,6 +17,7 @@ type SelectEntry struct { func NewSelectEntry(options []string) *SelectEntry { e := &SelectEntry{} e.ExtendBaseWidget(e) + e.Wrapping = fyne.TextTruncate e.options = options return e } diff --git a/vendor/fyne.io/fyne/v2/widget/slider.go b/vendor/fyne.io/fyne/v2/widget/slider.go index 9623555..63822a2 100644 --- a/vendor/fyne.io/fyne/v2/widget/slider.go +++ b/vendor/fyne.io/fyne/v2/widget/slider.go @@ -100,7 +100,14 @@ func (s *Slider) DragEnd() { func (s *Slider) Dragged(e *fyne.DragEvent) { ratio := s.getRatio(&(e.PointEvent)) + lastValue := s.Value + s.updateValue(ratio) + + if s.almostEqual(lastValue, s.Value) { + return + } + s.Refresh() if s.OnChanged != nil { @@ -156,10 +163,15 @@ func (s *Slider) clampValueToRange() { return } - i := -(math.Log10(s.Step)) - p := math.Pow(10, i) - - s.Value = float64(int(s.Value*p)) / p + rem := math.Mod(s.Value, s.Step) + if rem == 0 { + return + } + min := s.Value - rem + if rem > s.Step/2 { + min += s.Step + } + s.Value = min } func (s *Slider) updateValue(ratio float64) { @@ -174,9 +186,15 @@ func (s *Slider) SetValue(value float64) { return } + lastValue := s.Value + s.Value = value s.clampValueToRange() + if s.almostEqual(lastValue, s.Value) { + return + } + if s.OnChanged != nil { s.OnChanged(s.Value) } @@ -206,6 +224,11 @@ func (s *Slider) CreateRenderer() fyne.WidgetRenderer { return slide } +func (s *Slider) almostEqual(a, b float64) bool { + delta := math.Abs(a - b) + return delta <= s.Step/2 +} + // Unbind disconnects any configured data source from this Slider. // The current value will remain at the last value of the data source. // diff --git a/vendor/fyne.io/fyne/v2/widget/table.go b/vendor/fyne.io/fyne/v2/widget/table.go index f49c6aa..bca4eb6 100644 --- a/vendor/fyne.io/fyne/v2/widget/table.go +++ b/vendor/fyne.io/fyne/v2/widget/table.go @@ -330,7 +330,7 @@ func (t *tableRenderer) moveIndicators() { divs := 0 i := minCol - for x := offX + visibleColWidths[i]; i < minCol+colDivs; x += visibleColWidths[i] + separatorThickness { + for x := offX + visibleColWidths[i]; i < minCol+colDivs && divs < len(t.dividers); x += visibleColWidths[i] + separatorThickness { i++ t.dividers[divs].Move(fyne.NewPos(theme.Padding()+x-t.scroll.Offset.X, theme.Padding())) @@ -341,7 +341,7 @@ func (t *tableRenderer) moveIndicators() { i = 0 count := int(t.scroll.Offset.Y) % int(t.cellSize.Height+separatorThickness) - for y := theme.Padding() + t.scroll.Offset.Y - float32(count) - separatorThickness; y < t.scroll.Offset.Y+t.t.size.Height && i < rows-1; y += t.cellSize.Height + separatorThickness { + for y := theme.Padding() + t.scroll.Offset.Y - float32(count) - separatorThickness; y < t.scroll.Offset.Y+t.t.size.Height && i < rows-1 && divs < len(t.dividers); y += t.cellSize.Height + separatorThickness { if y < theme.Padding()+t.scroll.Offset.Y { continue } @@ -508,7 +508,20 @@ func (r *tableCellsRenderer) MinSize() fyne.Size { } else { fyne.LogError("Missing Length callback required for Table", nil) } - return fyne.NewSize(r.cells.cellSize.Width*float32(cols)+float32(cols-1), r.cells.cellSize.Height*float32(rows)+float32(rows-1)) + + width := float32(0) + cellWidth := r.cells.cellSize.Width + for col := 0; col < cols; col++ { + colWidth, ok := r.cells.t.columnWidths[col] + if ok { + width += colWidth + } else { + width += cellWidth + } + } + + separatorSize := theme.SeparatorThicknessSize() + return fyne.NewSize(width+float32(cols-1)*separatorSize, r.cells.cellSize.Height*float32(rows)+float32(rows-1)*separatorSize) } func (r *tableCellsRenderer) Refresh() { @@ -556,12 +569,12 @@ func (r *tableCellsRenderer) Refresh() { if c == nil { continue } - - c.Move(fyne.NewPos(theme.Padding()+cellOffset, - theme.Padding()+float32(row)*(r.cells.cellSize.Height+separatorThickness))) - c.Resize(fyne.NewSize(colWidth-theme.Padding()*2, r.cells.cellSize.Height-theme.Padding()*2)) } + c.Move(fyne.NewPos(theme.Padding()+cellOffset, + theme.Padding()+float32(row)*(r.cells.cellSize.Height+separatorThickness))) + c.Resize(fyne.NewSize(colWidth-theme.Padding()*2, r.cells.cellSize.Height-theme.Padding()*2)) + if updateCell != nil { updateCell(TableCellID{row, col}, c) } diff --git a/vendor/fyne.io/fyne/v2/widget/text.go b/vendor/fyne.io/fyne/v2/widget/text.go index 94e6819..3d98346 100644 --- a/vendor/fyne.io/fyne/v2/widget/text.go +++ b/vendor/fyne.io/fyne/v2/widget/text.go @@ -291,7 +291,7 @@ func (r *textRenderer) Layout(size fyne.Size) { xPos := theme.Padding() + r.provider.extraPad.Width yPos := theme.Padding() + r.provider.extraPad.Height lineHeight := r.provider.charMinSize().Height - lineSize := fyne.NewSize(size.Width-theme.Padding()*2, lineHeight) + lineSize := fyne.NewSize(size.Width-yPos*2, lineHeight) for i := 0; i < len(r.texts); i++ { text := r.texts[i] text.Resize(lineSize) diff --git a/vendor/github.com/fyne-io/mobile/app/GoNativeActivity.java b/vendor/github.com/fyne-io/mobile/app/GoNativeActivity.java index 71e3d7c..16df340 100644 --- a/vendor/github.com/fyne-io/mobile/app/GoNativeActivity.java +++ b/vendor/github.com/fyne-io/mobile/app/GoNativeActivity.java @@ -26,6 +26,7 @@ public class GoNativeActivity extends NativeActivity { private static GoNativeActivity goNativeActivity; private static final int FILE_OPEN_CODE = 1; + private static final int FILE_SAVE_CODE = 2; private static final int DEFAULT_INPUT_TYPE = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD; // this is required to force samsung keyboards to not suggest @@ -148,6 +149,21 @@ void doShowFileOpen(String mimes) { startActivityForResult(Intent.createChooser(intent, "Open File"), FILE_OPEN_CODE); } + static void showFileSave(String mimes) { + goNativeActivity.doShowFileSave(mimes); + } + + void doShowFileSave(String mimes) { + Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); + if (mimes.contains("|") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + intent.setType("*/*"); + intent.putExtra(Intent.EXTRA_MIME_TYPES, mimes.split("\\|")); + } else { + intent.setType(mimes); + } + intent.addCategory(Intent.CATEGORY_OPENABLE); + startActivityForResult(Intent.createChooser(intent, "Save File"), FILE_SAVE_CODE); + } static int getRune(int deviceId, int keyCode, int metaState) { try { int rune = KeyCharacterMap.load(deviceId).get(keyCode, metaState); @@ -241,7 +257,7 @@ public void afterTextChanged(Editable s) { @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // unhandled request - if (requestCode != FILE_OPEN_CODE) { + if (requestCode != FILE_OPEN_CODE && requestCode != FILE_SAVE_CODE) { return; } diff --git a/vendor/github.com/fyne-io/mobile/app/android.c b/vendor/github.com/fyne-io/mobile/app/android.c index 2ed86d5..0c1ed9e 100644 --- a/vendor/github.com/fyne-io/mobile/app/android.c +++ b/vendor/github.com/fyne-io/mobile/app/android.c @@ -51,6 +51,7 @@ static jmethodID key_rune_method; static jmethodID show_keyboard_method; static jmethodID hide_keyboard_method; static jmethodID show_file_open_method; +static jmethodID show_file_save_method; jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env; @@ -82,6 +83,7 @@ void ANativeActivity_onCreate(ANativeActivity *activity, void* savedState, size_ show_keyboard_method = find_static_method(env, current_class, "showKeyboard", "(I)V"); hide_keyboard_method = find_static_method(env, current_class, "hideKeyboard", "()V"); show_file_open_method = find_static_method(env, current_class, "showFileOpen", "(Ljava/lang/String;)V"); + show_file_save_method = find_static_method(env, current_class, "showFileSave", "(Ljava/lang/String;)V"); setCurrentContext(activity->vm, (*env)->NewGlobalRef(env, activity->clazz)); @@ -239,6 +241,16 @@ void showFileOpen(JNIEnv* env, char* mimes) { ); } +void showFileSave(JNIEnv* env, char* mimes) { + jstring mimesJString = (*env)->NewStringUTF(env, mimes); + (*env)->CallStaticVoidMethod( + env, + current_class, + show_file_save_method, + mimesJString + ); +} + void Java_org_golang_app_GoNativeActivity_filePickerReturned(JNIEnv *env, jclass clazz, jstring str) { const char* cstr = (*env)->GetStringUTFChars(env, str, JNI_FALSE); filePickerReturned((char*)cstr); @@ -255,4 +267,4 @@ void Java_org_golang_app_GoNativeActivity_keyboardTyped(JNIEnv *env, jclass claz void Java_org_golang_app_GoNativeActivity_keyboardDelete(JNIEnv *env, jclass clazz) { keyboardDelete(); -} \ No newline at end of file +} diff --git a/vendor/github.com/fyne-io/mobile/app/android.go b/vendor/github.com/fyne-io/mobile/app/android.go index 742dfff..7fc6590 100644 --- a/vendor/github.com/fyne-io/mobile/app/android.go +++ b/vendor/github.com/fyne-io/mobile/app/android.go @@ -35,8 +35,8 @@ package app #include #include -EGLDisplay display; -EGLSurface surface; +extern EGLDisplay display; +extern EGLSurface surface; char* createEGLSurface(ANativeWindow* window); char* destroyEGLSurface(); @@ -45,6 +45,7 @@ int32_t getKeyRune(JNIEnv* env, AInputEvent* e); void showKeyboard(JNIEnv* env, int keyboardType); void hideKeyboard(JNIEnv* env); void showFileOpen(JNIEnv* env, char* mimes); +void showFileSave(JNIEnv* env, char* mimes); void Java_org_golang_app_GoNativeActivity_filePickerReturned(JNIEnv *env, jclass clazz, jstring str); */ @@ -337,9 +338,7 @@ func insetsChanged(top, bottom, left, right int) { screenInsetTop, screenInsetBottom, screenInsetLeft, screenInsetRight = top, bottom, left, right } -func driverShowFileOpenPicker(callback func(string, func()), filter *FileFilter) { - fileCallback = callback - +func mimeStringFromFilter(filter *FileFilter) string { mimes := "*/*" if filter.MimeTypes != nil { mimes = strings.Join(filter.MimeTypes, "|") @@ -362,6 +361,13 @@ func driverShowFileOpenPicker(callback func(string, func()), filter *FileFilter) } mimes = strings.Join(mimeTypes, "|") } + return mimes +} + +func driverShowFileOpenPicker(callback func(string, func()), filter *FileFilter) { + fileCallback = callback + + mimes := mimeStringFromFilter(filter) mimeStr := C.CString(mimes) defer C.free(unsafe.Pointer(mimeStr)) @@ -377,6 +383,24 @@ func driverShowFileOpenPicker(callback func(string, func()), filter *FileFilter) } } +func driverShowFileSavePicker(callback func(string, func()), filter *FileFilter) { + fileCallback = callback + + mimes := mimeStringFromFilter(filter) + mimeStr := C.CString(mimes) + defer C.free(unsafe.Pointer(mimeStr)) + + save := func(vm, jniEnv, ctx uintptr) error { + env := (*C.JNIEnv)(unsafe.Pointer(jniEnv)) // not a Go heap pointer + C.showFileSave(env, mimeStr) + return nil + } + + if err := mobileinit.RunOnJVM(save); err != nil { + log.Fatalf("app: %v", err) + } +} + var mainUserFn func(App) var DisplayMetrics struct { diff --git a/vendor/github.com/fyne-io/mobile/app/app.go b/vendor/github.com/fyne-io/mobile/app/app.go index 44eccb6..b1ca18b 100644 --- a/vendor/github.com/fyne-io/mobile/app/app.go +++ b/vendor/github.com/fyne-io/mobile/app/app.go @@ -55,6 +55,7 @@ type App interface { ShowVirtualKeyboard(KeyboardType) HideVirtualKeyboard() ShowFileOpenPicker(func(string, func()), *FileFilter) + ShowFileSavePicker(func(string, func()), *FileFilter) } type FileFilter struct { @@ -149,6 +150,9 @@ func (a *app) HideVirtualKeyboard() { func (a *app) ShowFileOpenPicker(callback func(string, func()), filter *FileFilter) { driverShowFileOpenPicker(callback, filter) } +func (a *app) ShowFileSavePicker(callback func(string, func()), filter *FileFilter) { + driverShowFileSavePicker(callback, filter) +} type stopPumping struct{} diff --git a/vendor/github.com/fyne-io/mobile/app/darwin_desktop.go b/vendor/github.com/fyne-io/mobile/app/darwin_desktop.go index 54f8b2a..0e1a240 100644 --- a/vendor/github.com/fyne-io/mobile/app/darwin_desktop.go +++ b/vendor/github.com/fyne-io/mobile/app/darwin_desktop.go @@ -239,6 +239,10 @@ func driverHideVirtualKeyboard() { func driverShowFileOpenPicker(func(string, func()), *FileFilter) { } +// driverShowFileSavePicker does nothing on desktop +func driverShowFileSavePicker(func(string, func()), *FileFilter) { +} + // convRune marks the Carbon/Cocoa private-range unicode rune representing // a non-unicode key event to -1, used for Rune in the key package. // diff --git a/vendor/github.com/fyne-io/mobile/app/darwin_ios.go b/vendor/github.com/fyne-io/mobile/app/darwin_ios.go index eb65c66..dc30a97 100644 --- a/vendor/github.com/fyne-io/mobile/app/darwin_ios.go +++ b/vendor/github.com/fyne-io/mobile/app/darwin_ios.go @@ -28,6 +28,7 @@ void showKeyboard(int keyboardType); void hideKeyboard(); void showFileOpenPicker(char* mimes, char *exts); +void showFileSavePicker(char* mimes, char *exts); void closeFileResource(void* urlPtr); */ import "C" @@ -258,6 +259,19 @@ func (a *app) loop(ctx C.GLintptr) { } } +func cStringsForFilter(filter *FileFilter) (*C.char, *C.char) { + mimes := strings.Join(filter.MimeTypes, "|") + + // extensions must have the '.' removed for UTI lookups on iOS + extList := []string{} + for _, ext := range filter.Extensions { + extList = append(extList, ext[1:]) + } + exts := strings.Join(extList, "|") + + return C.CString(mimes), C.CString(exts) +} + // driverShowVirtualKeyboard requests the driver to show a virtual keyboard for text input func driverShowVirtualKeyboard(keyboard KeyboardType) { C.showKeyboard(C.int(int32(keyboard))) @@ -285,19 +299,19 @@ func filePickerReturned(str *C.char, urlPtr unsafe.Pointer) { func driverShowFileOpenPicker(callback func(string, func()), filter *FileFilter) { fileCallback = callback - mimes := strings.Join(filter.MimeTypes, "|") + mimeStr, extStr := cStringsForFilter(filter) + defer C.free(unsafe.Pointer(mimeStr)) + defer C.free(unsafe.Pointer(extStr)) - // extensions must have the '.' removed for UTI lookups on iOS - extList := []string{} - for _, ext := range filter.Extensions { - extList = append(extList, ext[1:]) - } - exts := strings.Join(extList, "|") + C.showFileOpenPicker(mimeStr, extStr) +} - mimeStr := C.CString(mimes) +func driverShowFileSavePicker(callback func(string, func()), filter *FileFilter) { + fileCallback = callback + + mimeStr, extStr := cStringsForFilter(filter) defer C.free(unsafe.Pointer(mimeStr)) - extStr := C.CString(exts) defer C.free(unsafe.Pointer(extStr)) - C.showFileOpenPicker(mimeStr, extStr) + C.showFileSavePicker(mimeStr, extStr) } diff --git a/vendor/github.com/fyne-io/mobile/app/darwin_ios.m b/vendor/github.com/fyne-io/mobile/app/darwin_ios.m index 7e9441a..0081dc8 100644 --- a/vendor/github.com/fyne-io/mobile/app/darwin_ios.m +++ b/vendor/github.com/fyne-io/mobile/app/darwin_ios.m @@ -294,9 +294,7 @@ void hideKeyboard() { }); } -void showFileOpenPicker(char* mimes, char *exts) { - GoAppAppDelegate *appDelegate = (GoAppAppDelegate *)[[UIApplication sharedApplication] delegate]; - +NSMutableArray *docTypesForMimeExts(char *mimes, char *exts) { NSMutableArray *docTypes = [NSMutableArray array]; if (mimes != NULL && strlen(mimes) > 0) { NSString *mimeList = [NSString stringWithUTF8String:mimes]; @@ -325,6 +323,14 @@ void showFileOpenPicker(char* mimes, char *exts) { [docTypes addObject:@"public.data"]; } + return docTypes; +} + +void showFileOpenPicker(char* mimes, char *exts) { + GoAppAppDelegate *appDelegate = (GoAppAppDelegate *)[[UIApplication sharedApplication] delegate]; + + NSMutableArray *docTypes = docTypesForMimeExts(mimes, exts); + UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:docTypes inMode:UIDocumentPickerModeOpen]; documentPicker.delegate = appDelegate; @@ -334,6 +340,27 @@ void showFileOpenPicker(char* mimes, char *exts) { }); } +void showFileSavePicker(char* mimes, char *exts) { + GoAppAppDelegate *appDelegate = (GoAppAppDelegate *)[[UIApplication sharedApplication] delegate]; + + NSMutableArray *docTypes = docTypesForMimeExts(mimes, exts); + + NSURL *temporaryDirectoryURL = [NSURL fileURLWithPath: NSTemporaryDirectory() isDirectory: YES]; + NSURL *temporaryFileURL = [temporaryDirectoryURL URLByAppendingPathComponent:@"filename"]; + + char* bytes = "\n"; + NSData *data = [NSData dataWithBytes:bytes length:1]; + BOOL ok = [data writeToURL:temporaryFileURL atomically:YES]; + + UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] + initWithURL:temporaryFileURL inMode:UIDocumentPickerModeMoveToService]; + documentPicker.delegate = appDelegate; + + dispatch_async(dispatch_get_main_queue(), ^{ + [appDelegate.controller presentViewController:documentPicker animated:YES completion:nil]; + }); +} + void closeFileResource(void* urlPtr) { if (urlPtr == NULL) { return; diff --git a/vendor/github.com/fyne-io/mobile/app/shiny.go b/vendor/github.com/fyne-io/mobile/app/shiny.go index c7e1adc..b7c1926 100644 --- a/vendor/github.com/fyne-io/mobile/app/shiny.go +++ b/vendor/github.com/fyne-io/mobile/app/shiny.go @@ -25,3 +25,7 @@ func driverHideVirtualKeyboard() { // driverShowFileOpenPicker does nothing on desktop func driverShowFileOpenPicker(func(string, func()), *FileFilter) { } + +// driverShowFileSavePicker does nothing on desktop +func driverShowFileSavePicker(func(string, func()), *FileFilter) { +} diff --git a/vendor/github.com/fyne-io/mobile/app/x11.go b/vendor/github.com/fyne-io/mobile/app/x11.go index e93dc4e..edc3977 100644 --- a/vendor/github.com/fyne-io/mobile/app/x11.go +++ b/vendor/github.com/fyne-io/mobile/app/x11.go @@ -135,3 +135,7 @@ func driverHideVirtualKeyboard() { // driverShowFileOpenPicker does nothing on desktop func driverShowFileOpenPicker(func(string, func()), *FileFilter) { } + +// driverShowFileSavePicker does nothing on desktop +func driverShowFileSavePicker(func(string, func()), *FileFilter) { +} diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/GLFW_C_REVISION.txt b/vendor/github.com/go-gl/glfw/v3.3/glfw/GLFW_C_REVISION.txt index 6a8efe1..2630b14 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/GLFW_C_REVISION.txt +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/GLFW_C_REVISION.txt @@ -1 +1 @@ -0a49ef0a00baa3ab520ddc452f0e3b1e099c5589 +746cdea490a70dd6747272a171b19e5ec1fb9900 diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/build.go b/vendor/github.com/go-gl/glfw/v3.3/glfw/build.go index acf4d92..b60c631 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/build.go +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/build.go @@ -7,8 +7,10 @@ package glfw #cgo windows CFLAGS: -D_GLFW_WIN32 -Iglfw/deps/mingw // Linker Options: -#cgo windows LDFLAGS: -lopengl32 -lgdi32 +#cgo windows LDFLAGS: -lgdi32 +#cgo !gles2,windows LDFLAGS: -lopengl32 +#cgo gles2,windows LDFLAGS: -lGLESv2 // Darwin Build Tags // ---------------- @@ -16,8 +18,10 @@ package glfw #cgo darwin CFLAGS: -D_GLFW_COCOA -Wno-deprecated-declarations // Linker Options: -#cgo darwin LDFLAGS: -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo +#cgo darwin LDFLAGS: -framework Cocoa -framework IOKit -framework CoreVideo +#cgo !gles2,darwin LDFLAGS: -framework OpenGL +#cgo gles2,darwin LDFLAGS: -lGLESv2 // Linux Build Tags // ---------------- diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/c_glfw_freebsd.go b/vendor/github.com/go-gl/glfw/v3.3/glfw/c_glfw_freebsd.go index 0b3a339..0112273 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/c_glfw_freebsd.go +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/c_glfw_freebsd.go @@ -7,7 +7,12 @@ package glfw #include "glfw/src/wl_init.c" #include "glfw/src/wl_monitor.c" #include "glfw/src/wl_window.c" - #include "glfw/src/wl_platform.h" + #include "glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.c" + #include "glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.c" + #include "glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c" + #include "glfw/src/wayland-viewporter-client-protocol.c" + #include "glfw/src/wayland-xdg-decoration-unstable-v1-client-protocol.c" + #include "glfw/src/wayland-xdg-shell-client-protocol.c" #endif #ifdef _GLFW_X11 #include "glfw/src/x11_init.c" diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/c_glfw_lin.go b/vendor/github.com/go-gl/glfw/v3.3/glfw/c_glfw_lin.go index b1918fc..67eb054 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/c_glfw_lin.go +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/c_glfw_lin.go @@ -7,7 +7,12 @@ package glfw #include "glfw/src/wl_init.c" #include "glfw/src/wl_monitor.c" #include "glfw/src/wl_window.c" - #include "glfw/src/wl_platform.h" + #include "glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.c" + #include "glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.c" + #include "glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c" + #include "glfw/src/wayland-viewporter-client-protocol.c" + #include "glfw/src/wayland-xdg-decoration-unstable-v1-client-protocol.c" + #include "glfw/src/wayland-xdg-shell-client-protocol.c" #endif #ifdef _GLFW_X11 #include "glfw/src/x11_init.c" diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/deps/linmath.h b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/deps/linmath.h index 9c2e2a0..0ab7a41 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/deps/linmath.h +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/deps/linmath.h @@ -237,9 +237,9 @@ static inline void mat4x4_rotate_Y(mat4x4 Q, mat4x4 M, float angle) float s = sinf(angle); float c = cosf(angle); mat4x4 R = { - { c, 0.f, s, 0.f}, + { c, 0.f, -s, 0.f}, { 0.f, 1.f, 0.f, 0.f}, - { -s, 0.f, c, 0.f}, + { s, 0.f, c, 0.f}, { 0.f, 0.f, 0.f, 1.f} }; mat4x4_mul(Q, M, R); diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/include/GLFW/glfw3.h b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/include/GLFW/glfw3.h index 66dff64..35bbf07 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/include/GLFW/glfw3.h +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/include/GLFW/glfw3.h @@ -52,7 +52,7 @@ extern "C" { * This is the reference documentation for OpenGL and OpenGL ES context related * functions. For more task-oriented information, see the @ref context_guide. */ -/*! @defgroup vulkan Vulkan reference +/*! @defgroup vulkan Vulkan support reference * @brief Functions and types related to Vulkan. * * This is the reference documentation for Vulkan related functions and types. @@ -193,7 +193,38 @@ extern "C" { #endif /*__APPLE__*/ -#elif !defined(GLFW_INCLUDE_NONE) +#elif defined(GLFW_INCLUDE_GLU) + + #if defined(__APPLE__) + + #if defined(GLFW_INCLUDE_GLU) + #include + #endif + + #else /*__APPLE__*/ + + #if defined(GLFW_INCLUDE_GLU) + #include + #endif + + #endif /*__APPLE__*/ + +#elif !defined(GLFW_INCLUDE_NONE) && \ + !defined(__gl_h_) && \ + !defined(__gles1_gl_h_) && \ + !defined(__gles2_gl2_h_) && \ + !defined(__gles2_gl3_h_) && \ + !defined(__gles2_gl31_h_) && \ + !defined(__gles2_gl32_h_) && \ + !defined(__gl_glcorearb_h_) && \ + !defined(__gl2_h_) /*legacy*/ && \ + !defined(__gl3_h_) /*legacy*/ && \ + !defined(__gl31_h_) /*legacy*/ && \ + !defined(__gl32_h_) /*legacy*/ && \ + !defined(__glcorearb_h_) /*legacy*/ && \ + !defined(__GL_H__) /*non-standard*/ && \ + !defined(__gltypes_h_) /*non-standard*/ && \ + !defined(__glee_h_) /*non-standard*/ #if defined(__APPLE__) @@ -201,9 +232,6 @@ extern "C" { #define GL_GLEXT_LEGACY #endif #include - #if defined(GLFW_INCLUDE_GLU) - #include - #endif #else /*__APPLE__*/ @@ -211,9 +239,6 @@ extern "C" { #if defined(GLFW_INCLUDE_GLEXT) #include #endif - #if defined(GLFW_INCLUDE_GLU) - #include - #endif #endif /*__APPLE__*/ @@ -270,7 +295,7 @@ extern "C" { * API changes. * @ingroup init */ -#define GLFW_VERSION_REVISION 2 +#define GLFW_VERSION_REVISION 3 /*! @} */ /*! @brief One. @@ -949,9 +974,9 @@ extern "C" { * and [attribute](@ref GLFW_OPENGL_FORWARD_COMPAT_attrib). */ #define GLFW_OPENGL_FORWARD_COMPAT 0x00022006 -/*! @brief OpenGL debug context hint and attribute. +/*! @brief Debug mode context hint and attribute. * - * OpenGL debug context [hint](@ref GLFW_OPENGL_DEBUG_CONTEXT_hint) and + * Debug mode context [hint](@ref GLFW_OPENGL_DEBUG_CONTEXT_hint) and * [attribute](@ref GLFW_OPENGL_DEBUG_CONTEXT_attrib). */ #define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 @@ -1328,7 +1353,7 @@ typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); * @endcode * * @param[in] window The window that was maximized or restored. - * @param[in] iconified `GLFW_TRUE` if the window was maximized, or + * @param[in] maximized `GLFW_TRUE` if the window was maximized, or * `GLFW_FALSE` if it was restored. * * @sa @ref window_maximize @@ -1753,6 +1778,10 @@ typedef struct GLFWgamepadstate * bundle, if present. This can be disabled with the @ref * GLFW_COCOA_CHDIR_RESOURCES init hint. * + * @remark @x11 This function will set the `LC_CTYPE` category of the + * application locale according to the current environment if that category is + * still "C". This is because the "C" locale breaks Unicode text input. + * * @thread_safety This function must only be called from the main thread. * * @sa @ref intro_init @@ -1776,6 +1805,8 @@ GLFWAPI int glfwInit(void); * call this function, as it is called by @ref glfwInit before it returns * failure. * + * This function has no effect if GLFW is not initialized. + * * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. * * @remark This function may be called before @ref glfwInit. diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_init.m b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_init.m index 579b6e6..209639e 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_init.m +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_init.m @@ -428,9 +428,6 @@ - (void)applicationWillFinishLaunching:(NSNotification *)notification { if (_glfw.hints.init.ns.menubar) { - // In case we are unbundled, make us a proper UI application - [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; - // Menu bar setup must go between sharedApplication and finishLaunching // in order to properly emulate the behavior of NSApplicationMain @@ -449,6 +446,11 @@ - (void)applicationDidFinishLaunching:(NSNotification *)notification { _glfw.ns.finishedLaunching = GLFW_TRUE; _glfwPlatformPostEmptyEvent(); + + // In case we are unbundled, make us a proper UI application + if (_glfw.hints.init.ns.menubar) + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + [NSApp stop:nil]; } diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_monitor.m b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_monitor.m index 8ef94a3..55638cf 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_monitor.m +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_monitor.m @@ -39,8 +39,21 @@ // Get the name of the specified display, or NULL // -static char* getDisplayName(CGDirectDisplayID displayID) +static char* getMonitorName(CGDirectDisplayID displayID, NSScreen* screen) { + // IOKit doesn't work on Apple Silicon anymore + // Luckily, 10.15 introduced -[NSScreen localizedName]. + // Use it if available, and fall back to IOKit otherwise. + if (screen) + { + if ([screen respondsToSelector:@selector(localizedName)]) + { + NSString* name = [screen valueForKey:@"localizedName"]; + if (name) + return _glfw_strdup([name UTF8String]); + } + } + io_iterator_t it; io_service_t service; CFDictionaryRef info; @@ -209,31 +222,6 @@ static void endFadeReservation(CGDisplayFadeReservationToken token) } } -// Finds and caches the NSScreen corresponding to the specified monitor -// -static GLFWbool refreshMonitorScreen(_GLFWmonitor* monitor) -{ - if (monitor->ns.screen) - return GLFW_TRUE; - - for (NSScreen* screen in [NSScreen screens]) - { - NSNumber* displayID = [screen deviceDescription][@"NSScreenNumber"]; - - // HACK: Compare unit numbers instead of display IDs to work around - // display replacement on machines with automatic graphics - // switching - if (monitor->ns.unitNumber == CGDisplayUnitNumber([displayID unsignedIntValue])) - { - monitor->ns.screen = screen; - return GLFW_TRUE; - } - } - - _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to find a screen for monitor"); - return GLFW_FALSE; -} - // Returns the display refresh rate queried from the I/O registry // static double getFallbackRefreshRate(CGDirectDisplayID displayID) @@ -277,14 +265,20 @@ static double getFallbackRefreshRate(CGDirectDisplayID displayID) CFSTR("IOFBCurrentPixelCount"), kCFAllocatorDefault, kNilOptions); - if (!clockRef || !countRef) - break; uint32_t clock = 0, count = 0; - CFNumberGetValue(clockRef, kCFNumberIntType, &clock); - CFNumberGetValue(countRef, kCFNumberIntType, &count); - CFRelease(clockRef); - CFRelease(countRef); + + if (clockRef) + { + CFNumberGetValue(clockRef, kCFNumberIntType, &clock); + CFRelease(clockRef); + } + + if (countRef) + { + CFNumberGetValue(countRef, kCFNumberIntType, &count); + CFRelease(countRef); + } if (clock > 0 && count > 0) refreshRate = clock / (double) count; @@ -328,27 +322,46 @@ void _glfwPollMonitorsNS(void) if (CGDisplayIsAsleep(displays[i])) continue; + const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]); + NSScreen* screen = nil; + + for (screen in [NSScreen screens]) + { + NSNumber* screenNumber = [screen deviceDescription][@"NSScreenNumber"]; + + // HACK: Compare unit numbers instead of display IDs to work around + // display replacement on machines with automatic graphics + // switching + if (CGDisplayUnitNumber([screenNumber unsignedIntValue]) == unitNumber) + break; + } + // HACK: Compare unit numbers instead of display IDs to work around // display replacement on machines with automatic graphics // switching - const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]); - for (uint32_t j = 0; j < disconnectedCount; j++) + uint32_t j; + for (j = 0; j < disconnectedCount; j++) { if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber) { + disconnected[j]->ns.screen = screen; disconnected[j] = NULL; break; } } + if (j < disconnectedCount) + continue; + const CGSize size = CGDisplayScreenSize(displays[i]); - char* name = getDisplayName(displays[i]); + char* name = getMonitorName(displays[i], screen); if (!name) name = _glfw_strdup("Unknown"); _GLFWmonitor* monitor = _glfwAllocMonitor(name, size.width, size.height); monitor->ns.displayID = displays[i]; monitor->ns.unitNumber = unitNumber; + monitor->ns.screen = screen; free(name); @@ -457,8 +470,11 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, { @autoreleasepool { - if (!refreshMonitorScreen(monitor)) - return; + if (!monitor->ns.screen) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Cannot query content scale without screen"); + } const NSRect points = [monitor->ns.screen frame]; const NSRect pixels = [monitor->ns.screen convertRectToBacking:points]; @@ -477,8 +493,11 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, { @autoreleasepool { - if (!refreshMonitorScreen(monitor)) - return; + if (!monitor->ns.screen) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Cannot query workarea without screen"); + } const NSRect frameRect = [monitor->ns.screen visibleFrame]; @@ -521,7 +540,7 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, } // Skip duplicate modes - if (i < *count) + if (j < *count) continue; (*count)++; diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_platform.h b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_platform.h index 15c2169..05c23b7 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_platform.h +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_platform.h @@ -92,7 +92,7 @@ typedef VkResult (APIENTRY *PFN_vkCreateMetalSurfaceEXT)(VkInstance,const VkMeta #define _glfw_dlclose(handle) dlclose(handle) #define _glfw_dlsym(handle, name) dlsym(handle, name) -#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->ns.view) +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->ns.layer) #define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns @@ -121,6 +121,7 @@ typedef struct _GLFWwindowNS id layer; GLFWbool maximized; + GLFWbool occluded; GLFWbool retina; // Cached window properties to filter out duplicate events diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_window.m b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_window.m index 129e975..9fa72a6 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_window.m +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/cocoa_window.m @@ -322,6 +322,14 @@ - (void)windowDidResignKey:(NSNotification *)notification _glfwInputWindowFocus(window, GLFW_FALSE); } +- (void)windowDidChangeOcclusionState:(NSNotification* )notification +{ + if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible) + window->ns.occluded = GLFW_FALSE; + else + window->ns.occluded = GLFW_TRUE; +} + @end @@ -723,14 +731,24 @@ - (void)insertText:(id)string replacementRange:(NSRange)replacementRange else characters = (NSString*) string; - const NSUInteger length = [characters length]; - for (NSUInteger i = 0; i < length; i++) + NSRange range = NSMakeRange(0, [characters length]); + while (range.length) { - const unichar codepoint = [characters characterAtIndex:i]; - if ((codepoint & 0xff00) == 0xf700) - continue; + uint32_t codepoint = 0; + + if ([characters getBytes:&codepoint + maxLength:sizeof(codepoint) + usedLength:NULL + encoding:NSUTF32StringEncoding + options:0 + range:range + remainingRange:&range]) + { + if (codepoint >= 0xf700 && codepoint <= 0xf7ff) + continue; - _glfwInputChar(window, codepoint, mods, plain); + _glfwInputChar(window, codepoint, mods, plain); + } } } @@ -901,6 +919,11 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, } else if (ctxconfig->source == GLFW_EGL_CONTEXT_API) { + // EGL implementation on macOS use CALayer* EGLNativeWindowType so we + // need to get the layer for EGL window surface creation. + [window->ns.view setWantsLayer:YES]; + window->ns.layer = [window->ns.view layer]; + if (!_glfwInitEGL()) return GLFW_FALSE; if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/egl_context.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/egl_context.c index e458bfb..6288fb7 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/egl_context.c +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/egl_context.c @@ -588,18 +588,16 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, } // Set up attributes for surface creation - { - int index = 0; - - if (fbconfig->sRGB) - { - if (_glfw.egl.KHR_gl_colorspace) - setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); - } + index = 0; - setAttrib(EGL_NONE, EGL_NONE); + if (fbconfig->sRGB) + { + if (_glfw.egl.KHR_gl_colorspace) + setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); } + setAttrib(EGL_NONE, EGL_NONE); + window->context.egl.surface = eglCreateWindowSurface(_glfw.egl.display, config, diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/internal.h b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/internal.h index 92b9497..91631c0 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/internal.h +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/internal.h @@ -342,9 +342,9 @@ struct _GLFWcontext int robustness; int release; - PFNGLGETSTRINGIPROC GetStringi; + PFNGLGETSTRINGIPROC GetStringi; PFNGLGETINTEGERVPROC GetIntegerv; - PFNGLGETSTRINGPROC GetString; + PFNGLGETSTRINGPROC GetString; _GLFWmakecontextcurrentfun makeCurrent; _GLFWswapbuffersfun swapBuffers; @@ -396,23 +396,23 @@ struct _GLFWwindow _GLFWcontext context; struct { - GLFWwindowposfun pos; - GLFWwindowsizefun size; - GLFWwindowclosefun close; - GLFWwindowrefreshfun refresh; - GLFWwindowfocusfun focus; - GLFWwindowiconifyfun iconify; - GLFWwindowmaximizefun maximize; - GLFWframebuffersizefun fbsize; + GLFWwindowposfun pos; + GLFWwindowsizefun size; + GLFWwindowclosefun close; + GLFWwindowrefreshfun refresh; + GLFWwindowfocusfun focus; + GLFWwindowiconifyfun iconify; + GLFWwindowmaximizefun maximize; + GLFWframebuffersizefun fbsize; GLFWwindowcontentscalefun scale; - GLFWmousebuttonfun mouseButton; - GLFWcursorposfun cursorPos; - GLFWcursorenterfun cursorEnter; - GLFWscrollfun scroll; - GLFWkeyfun key; - GLFWcharfun character; - GLFWcharmodsfun charmods; - GLFWdropfun drop; + GLFWmousebuttonfun mouseButton; + GLFWcursorposfun cursorPos; + GLFWcursorenterfun cursorEnter; + GLFWscrollfun scroll; + GLFWkeyfun key; + GLFWcharfun character; + GLFWcharmodsfun charmods; + GLFWdropfun drop; } callbacks; // This is defined in the window API's platform.h diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/nsgl_context.m b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/nsgl_context.m index 3bcfafc..1028684 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/nsgl_context.m +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/nsgl_context.m @@ -51,7 +51,7 @@ static void swapBuffersNSGL(_GLFWwindow* window) // HACK: Simulate vsync with usleep as NSGL swap interval does not apply to // windows with a non-visible occlusion state - if (!([window->ns.object occlusionState] & NSWindowOcclusionStateVisible)) + if (window->ns.occluded) { int interval = 0; [window->context.nsgl.object getValues:&interval diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.c new file mode 100644 index 0000000..6a70a81 --- /dev/null +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.c @@ -0,0 +1,68 @@ +/* Generated by wayland-scanner */ + +/* + * Copyright © 2015 Samsung Electronics Co., Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface zwp_idle_inhibitor_v1_interface; + +static const struct wl_interface *idle_inhibit_unstable_v1_types[] = { + &zwp_idle_inhibitor_v1_interface, + &wl_surface_interface, +}; + +static const struct wl_message zwp_idle_inhibit_manager_v1_requests[] = { + { "destroy", "", idle_inhibit_unstable_v1_types + 0 }, + { "create_inhibitor", "no", idle_inhibit_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_idle_inhibit_manager_v1_interface = { + "zwp_idle_inhibit_manager_v1", 1, + 2, zwp_idle_inhibit_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message zwp_idle_inhibitor_v1_requests[] = { + { "destroy", "", idle_inhibit_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_idle_inhibitor_v1_interface = { + "zwp_idle_inhibitor_v1", 1, + 1, zwp_idle_inhibitor_v1_requests, + 0, NULL, +}; + diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.h b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.h new file mode 100644 index 0000000..7aa028e --- /dev/null +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-idle-inhibit-unstable-v1-client-protocol.h @@ -0,0 +1,230 @@ +/* Generated by wayland-scanner */ + +#ifndef IDLE_INHIBIT_UNSTABLE_V1_CLIENT_PROTOCOL_H +#define IDLE_INHIBIT_UNSTABLE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_idle_inhibit_unstable_v1 The idle_inhibit_unstable_v1 protocol + * @section page_ifaces_idle_inhibit_unstable_v1 Interfaces + * - @subpage page_iface_zwp_idle_inhibit_manager_v1 - control behavior when display idles + * - @subpage page_iface_zwp_idle_inhibitor_v1 - context object for inhibiting idle behavior + * @section page_copyright_idle_inhibit_unstable_v1 Copyright + *
+ *
+ * Copyright © 2015 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_surface; +struct zwp_idle_inhibit_manager_v1; +struct zwp_idle_inhibitor_v1; + +/** + * @page page_iface_zwp_idle_inhibit_manager_v1 zwp_idle_inhibit_manager_v1 + * @section page_iface_zwp_idle_inhibit_manager_v1_desc Description + * + * This interface permits inhibiting the idle behavior such as screen + * blanking, locking, and screensaving. The client binds the idle manager + * globally, then creates idle-inhibitor objects for each surface. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * interface version number is reset. + * @section page_iface_zwp_idle_inhibit_manager_v1_api API + * See @ref iface_zwp_idle_inhibit_manager_v1. + */ +/** + * @defgroup iface_zwp_idle_inhibit_manager_v1 The zwp_idle_inhibit_manager_v1 interface + * + * This interface permits inhibiting the idle behavior such as screen + * blanking, locking, and screensaving. The client binds the idle manager + * globally, then creates idle-inhibitor objects for each surface. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * interface version number is reset. + */ +extern const struct wl_interface zwp_idle_inhibit_manager_v1_interface; +/** + * @page page_iface_zwp_idle_inhibitor_v1 zwp_idle_inhibitor_v1 + * @section page_iface_zwp_idle_inhibitor_v1_desc Description + * + * An idle inhibitor prevents the output that the associated surface is + * visible on from being set to a state where it is not visually usable due + * to lack of user interaction (e.g. blanked, dimmed, locked, set to power + * save, etc.) Any screensaver processes are also blocked from displaying. + * + * If the surface is destroyed, unmapped, becomes occluded, loses + * visibility, or otherwise becomes not visually relevant for the user, the + * idle inhibitor will not be honored by the compositor; if the surface + * subsequently regains visibility the inhibitor takes effect once again. + * Likewise, the inhibitor isn't honored if the system was already idled at + * the time the inhibitor was established, although if the system later + * de-idles and re-idles the inhibitor will take effect. + * @section page_iface_zwp_idle_inhibitor_v1_api API + * See @ref iface_zwp_idle_inhibitor_v1. + */ +/** + * @defgroup iface_zwp_idle_inhibitor_v1 The zwp_idle_inhibitor_v1 interface + * + * An idle inhibitor prevents the output that the associated surface is + * visible on from being set to a state where it is not visually usable due + * to lack of user interaction (e.g. blanked, dimmed, locked, set to power + * save, etc.) Any screensaver processes are also blocked from displaying. + * + * If the surface is destroyed, unmapped, becomes occluded, loses + * visibility, or otherwise becomes not visually relevant for the user, the + * idle inhibitor will not be honored by the compositor; if the surface + * subsequently regains visibility the inhibitor takes effect once again. + * Likewise, the inhibitor isn't honored if the system was already idled at + * the time the inhibitor was established, although if the system later + * de-idles and re-idles the inhibitor will take effect. + */ +extern const struct wl_interface zwp_idle_inhibitor_v1_interface; + +#define ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY 0 +#define ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR 1 + + +/** + * @ingroup iface_zwp_idle_inhibit_manager_v1 + */ +#define ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_idle_inhibit_manager_v1 + */ +#define ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR_SINCE_VERSION 1 + +/** @ingroup iface_zwp_idle_inhibit_manager_v1 */ +static inline void +zwp_idle_inhibit_manager_v1_set_user_data(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_idle_inhibit_manager_v1, user_data); +} + +/** @ingroup iface_zwp_idle_inhibit_manager_v1 */ +static inline void * +zwp_idle_inhibit_manager_v1_get_user_data(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_idle_inhibit_manager_v1); +} + +static inline uint32_t +zwp_idle_inhibit_manager_v1_get_version(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibit_manager_v1); +} + +/** + * @ingroup iface_zwp_idle_inhibit_manager_v1 + * + * Destroy the inhibit manager. + */ +static inline void +zwp_idle_inhibit_manager_v1_destroy(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1) +{ + wl_proxy_marshal((struct wl_proxy *) zwp_idle_inhibit_manager_v1, + ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwp_idle_inhibit_manager_v1); +} + +/** + * @ingroup iface_zwp_idle_inhibit_manager_v1 + * + * Create a new inhibitor object associated with the given surface. + */ +static inline struct zwp_idle_inhibitor_v1 * +zwp_idle_inhibit_manager_v1_create_inhibitor(struct zwp_idle_inhibit_manager_v1 *zwp_idle_inhibit_manager_v1, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_idle_inhibit_manager_v1, + ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR, &zwp_idle_inhibitor_v1_interface, NULL, surface); + + return (struct zwp_idle_inhibitor_v1 *) id; +} + +#define ZWP_IDLE_INHIBITOR_V1_DESTROY 0 + + +/** + * @ingroup iface_zwp_idle_inhibitor_v1 + */ +#define ZWP_IDLE_INHIBITOR_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_idle_inhibitor_v1 */ +static inline void +zwp_idle_inhibitor_v1_set_user_data(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_idle_inhibitor_v1, user_data); +} + +/** @ingroup iface_zwp_idle_inhibitor_v1 */ +static inline void * +zwp_idle_inhibitor_v1_get_user_data(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_idle_inhibitor_v1); +} + +static inline uint32_t +zwp_idle_inhibitor_v1_get_version(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_idle_inhibitor_v1); +} + +/** + * @ingroup iface_zwp_idle_inhibitor_v1 + * + * Remove the inhibitor effect from the associated wl_surface. + */ +static inline void +zwp_idle_inhibitor_v1_destroy(struct zwp_idle_inhibitor_v1 *zwp_idle_inhibitor_v1) +{ + wl_proxy_marshal((struct wl_proxy *) zwp_idle_inhibitor_v1, + ZWP_IDLE_INHIBITOR_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwp_idle_inhibitor_v1); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.c new file mode 100644 index 0000000..f97c52e --- /dev/null +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.c @@ -0,0 +1,108 @@ +/* Generated by wayland-scanner */ + +/* + * Copyright © 2014 Jonas Ådahl + * Copyright © 2015 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_pointer_interface; +extern const struct wl_interface wl_region_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface zwp_confined_pointer_v1_interface; +extern const struct wl_interface zwp_locked_pointer_v1_interface; + +static const struct wl_interface *pointer_constraints_unstable_v1_types[] = { + NULL, + NULL, + &zwp_locked_pointer_v1_interface, + &wl_surface_interface, + &wl_pointer_interface, + &wl_region_interface, + NULL, + &zwp_confined_pointer_v1_interface, + &wl_surface_interface, + &wl_pointer_interface, + &wl_region_interface, + NULL, + &wl_region_interface, + &wl_region_interface, +}; + +static const struct wl_message zwp_pointer_constraints_v1_requests[] = { + { "destroy", "", pointer_constraints_unstable_v1_types + 0 }, + { "lock_pointer", "noo?ou", pointer_constraints_unstable_v1_types + 2 }, + { "confine_pointer", "noo?ou", pointer_constraints_unstable_v1_types + 7 }, +}; + +WL_PRIVATE const struct wl_interface zwp_pointer_constraints_v1_interface = { + "zwp_pointer_constraints_v1", 1, + 3, zwp_pointer_constraints_v1_requests, + 0, NULL, +}; + +static const struct wl_message zwp_locked_pointer_v1_requests[] = { + { "destroy", "", pointer_constraints_unstable_v1_types + 0 }, + { "set_cursor_position_hint", "ff", pointer_constraints_unstable_v1_types + 0 }, + { "set_region", "?o", pointer_constraints_unstable_v1_types + 12 }, +}; + +static const struct wl_message zwp_locked_pointer_v1_events[] = { + { "locked", "", pointer_constraints_unstable_v1_types + 0 }, + { "unlocked", "", pointer_constraints_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_locked_pointer_v1_interface = { + "zwp_locked_pointer_v1", 1, + 3, zwp_locked_pointer_v1_requests, + 2, zwp_locked_pointer_v1_events, +}; + +static const struct wl_message zwp_confined_pointer_v1_requests[] = { + { "destroy", "", pointer_constraints_unstable_v1_types + 0 }, + { "set_region", "?o", pointer_constraints_unstable_v1_types + 13 }, +}; + +static const struct wl_message zwp_confined_pointer_v1_events[] = { + { "confined", "", pointer_constraints_unstable_v1_types + 0 }, + { "unconfined", "", pointer_constraints_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_confined_pointer_v1_interface = { + "zwp_confined_pointer_v1", 1, + 2, zwp_confined_pointer_v1_requests, + 2, zwp_confined_pointer_v1_events, +}; + diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.h b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.h new file mode 100644 index 0000000..8ae3420 --- /dev/null +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-pointer-constraints-unstable-v1-client-protocol.h @@ -0,0 +1,649 @@ +/* Generated by wayland-scanner */ + +#ifndef POINTER_CONSTRAINTS_UNSTABLE_V1_CLIENT_PROTOCOL_H +#define POINTER_CONSTRAINTS_UNSTABLE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_pointer_constraints_unstable_v1 The pointer_constraints_unstable_v1 protocol + * protocol for constraining pointer motions + * + * @section page_desc_pointer_constraints_unstable_v1 Description + * + * This protocol specifies a set of interfaces used for adding constraints to + * the motion of a pointer. Possible constraints include confining pointer + * motions to a given region, or locking it to its current position. + * + * In order to constrain the pointer, a client must first bind the global + * interface "wp_pointer_constraints" which, if a compositor supports pointer + * constraints, is exposed by the registry. Using the bound global object, the + * client uses the request that corresponds to the type of constraint it wants + * to make. See wp_pointer_constraints for more details. + * + * Warning! The protocol described in this file is experimental and backward + * incompatible changes may be made. Backward compatible changes may be added + * together with the corresponding interface version bump. Backward + * incompatible changes are done by bumping the version number in the protocol + * and interface names and resetting the interface version. Once the protocol + * is to be declared stable, the 'z' prefix and the version number in the + * protocol and interface names are removed and the interface version number is + * reset. + * + * @section page_ifaces_pointer_constraints_unstable_v1 Interfaces + * - @subpage page_iface_zwp_pointer_constraints_v1 - constrain the movement of a pointer + * - @subpage page_iface_zwp_locked_pointer_v1 - receive relative pointer motion events + * - @subpage page_iface_zwp_confined_pointer_v1 - confined pointer object + * @section page_copyright_pointer_constraints_unstable_v1 Copyright + *
+ *
+ * Copyright © 2014      Jonas Ådahl
+ * Copyright © 2015      Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_pointer; +struct wl_region; +struct wl_surface; +struct zwp_confined_pointer_v1; +struct zwp_locked_pointer_v1; +struct zwp_pointer_constraints_v1; + +/** + * @page page_iface_zwp_pointer_constraints_v1 zwp_pointer_constraints_v1 + * @section page_iface_zwp_pointer_constraints_v1_desc Description + * + * The global interface exposing pointer constraining functionality. It + * exposes two requests: lock_pointer for locking the pointer to its + * position, and confine_pointer for locking the pointer to a region. + * + * The lock_pointer and confine_pointer requests create the objects + * wp_locked_pointer and wp_confined_pointer respectively, and the client can + * use these objects to interact with the lock. + * + * For any surface, only one lock or confinement may be active across all + * wl_pointer objects of the same seat. If a lock or confinement is requested + * when another lock or confinement is active or requested on the same surface + * and with any of the wl_pointer objects of the same seat, an + * 'already_constrained' error will be raised. + * @section page_iface_zwp_pointer_constraints_v1_api API + * See @ref iface_zwp_pointer_constraints_v1. + */ +/** + * @defgroup iface_zwp_pointer_constraints_v1 The zwp_pointer_constraints_v1 interface + * + * The global interface exposing pointer constraining functionality. It + * exposes two requests: lock_pointer for locking the pointer to its + * position, and confine_pointer for locking the pointer to a region. + * + * The lock_pointer and confine_pointer requests create the objects + * wp_locked_pointer and wp_confined_pointer respectively, and the client can + * use these objects to interact with the lock. + * + * For any surface, only one lock or confinement may be active across all + * wl_pointer objects of the same seat. If a lock or confinement is requested + * when another lock or confinement is active or requested on the same surface + * and with any of the wl_pointer objects of the same seat, an + * 'already_constrained' error will be raised. + */ +extern const struct wl_interface zwp_pointer_constraints_v1_interface; +/** + * @page page_iface_zwp_locked_pointer_v1 zwp_locked_pointer_v1 + * @section page_iface_zwp_locked_pointer_v1_desc Description + * + * The wp_locked_pointer interface represents a locked pointer state. + * + * While the lock of this object is active, the wl_pointer objects of the + * associated seat will not emit any wl_pointer.motion events. + * + * This object will send the event 'locked' when the lock is activated. + * Whenever the lock is activated, it is guaranteed that the locked surface + * will already have received pointer focus and that the pointer will be + * within the region passed to the request creating this object. + * + * To unlock the pointer, send the destroy request. This will also destroy + * the wp_locked_pointer object. + * + * If the compositor decides to unlock the pointer the unlocked event is + * sent. See wp_locked_pointer.unlock for details. + * + * When unlocking, the compositor may warp the cursor position to the set + * cursor position hint. If it does, it will not result in any relative + * motion events emitted via wp_relative_pointer. + * + * If the surface the lock was requested on is destroyed and the lock is not + * yet activated, the wp_locked_pointer object is now defunct and must be + * destroyed. + * @section page_iface_zwp_locked_pointer_v1_api API + * See @ref iface_zwp_locked_pointer_v1. + */ +/** + * @defgroup iface_zwp_locked_pointer_v1 The zwp_locked_pointer_v1 interface + * + * The wp_locked_pointer interface represents a locked pointer state. + * + * While the lock of this object is active, the wl_pointer objects of the + * associated seat will not emit any wl_pointer.motion events. + * + * This object will send the event 'locked' when the lock is activated. + * Whenever the lock is activated, it is guaranteed that the locked surface + * will already have received pointer focus and that the pointer will be + * within the region passed to the request creating this object. + * + * To unlock the pointer, send the destroy request. This will also destroy + * the wp_locked_pointer object. + * + * If the compositor decides to unlock the pointer the unlocked event is + * sent. See wp_locked_pointer.unlock for details. + * + * When unlocking, the compositor may warp the cursor position to the set + * cursor position hint. If it does, it will not result in any relative + * motion events emitted via wp_relative_pointer. + * + * If the surface the lock was requested on is destroyed and the lock is not + * yet activated, the wp_locked_pointer object is now defunct and must be + * destroyed. + */ +extern const struct wl_interface zwp_locked_pointer_v1_interface; +/** + * @page page_iface_zwp_confined_pointer_v1 zwp_confined_pointer_v1 + * @section page_iface_zwp_confined_pointer_v1_desc Description + * + * The wp_confined_pointer interface represents a confined pointer state. + * + * This object will send the event 'confined' when the confinement is + * activated. Whenever the confinement is activated, it is guaranteed that + * the surface the pointer is confined to will already have received pointer + * focus and that the pointer will be within the region passed to the request + * creating this object. It is up to the compositor to decide whether this + * requires some user interaction and if the pointer will warp to within the + * passed region if outside. + * + * To unconfine the pointer, send the destroy request. This will also destroy + * the wp_confined_pointer object. + * + * If the compositor decides to unconfine the pointer the unconfined event is + * sent. The wp_confined_pointer object is at this point defunct and should + * be destroyed. + * @section page_iface_zwp_confined_pointer_v1_api API + * See @ref iface_zwp_confined_pointer_v1. + */ +/** + * @defgroup iface_zwp_confined_pointer_v1 The zwp_confined_pointer_v1 interface + * + * The wp_confined_pointer interface represents a confined pointer state. + * + * This object will send the event 'confined' when the confinement is + * activated. Whenever the confinement is activated, it is guaranteed that + * the surface the pointer is confined to will already have received pointer + * focus and that the pointer will be within the region passed to the request + * creating this object. It is up to the compositor to decide whether this + * requires some user interaction and if the pointer will warp to within the + * passed region if outside. + * + * To unconfine the pointer, send the destroy request. This will also destroy + * the wp_confined_pointer object. + * + * If the compositor decides to unconfine the pointer the unconfined event is + * sent. The wp_confined_pointer object is at this point defunct and should + * be destroyed. + */ +extern const struct wl_interface zwp_confined_pointer_v1_interface; + +#ifndef ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM +#define ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM +/** + * @ingroup iface_zwp_pointer_constraints_v1 + * wp_pointer_constraints error values + * + * These errors can be emitted in response to wp_pointer_constraints + * requests. + */ +enum zwp_pointer_constraints_v1_error { + /** + * pointer constraint already requested on that surface + */ + ZWP_POINTER_CONSTRAINTS_V1_ERROR_ALREADY_CONSTRAINED = 1, +}; +#endif /* ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM */ + +#ifndef ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM +#define ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM +/** + * @ingroup iface_zwp_pointer_constraints_v1 + * the pointer constraint may reactivate + * + * A persistent pointer constraint may again reactivate once it has + * been deactivated. See the corresponding deactivation event + * (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) for + * details. + */ +enum zwp_pointer_constraints_v1_lifetime { + ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT = 1, + ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT = 2, +}; +#endif /* ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM */ + +#define ZWP_POINTER_CONSTRAINTS_V1_DESTROY 0 +#define ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER 1 +#define ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER 2 + + +/** + * @ingroup iface_zwp_pointer_constraints_v1 + */ +#define ZWP_POINTER_CONSTRAINTS_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_pointer_constraints_v1 + */ +#define ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_pointer_constraints_v1 + */ +#define ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER_SINCE_VERSION 1 + +/** @ingroup iface_zwp_pointer_constraints_v1 */ +static inline void +zwp_pointer_constraints_v1_set_user_data(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_pointer_constraints_v1, user_data); +} + +/** @ingroup iface_zwp_pointer_constraints_v1 */ +static inline void * +zwp_pointer_constraints_v1_get_user_data(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_pointer_constraints_v1); +} + +static inline uint32_t +zwp_pointer_constraints_v1_get_version(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_pointer_constraints_v1); +} + +/** + * @ingroup iface_zwp_pointer_constraints_v1 + * + * Used by the client to notify the server that it will no longer use this + * pointer constraints object. + */ +static inline void +zwp_pointer_constraints_v1_destroy(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1) +{ + wl_proxy_marshal((struct wl_proxy *) zwp_pointer_constraints_v1, + ZWP_POINTER_CONSTRAINTS_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwp_pointer_constraints_v1); +} + +/** + * @ingroup iface_zwp_pointer_constraints_v1 + * + * The lock_pointer request lets the client request to disable movements of + * the virtual pointer (i.e. the cursor), effectively locking the pointer + * to a position. This request may not take effect immediately; in the + * future, when the compositor deems implementation-specific constraints + * are satisfied, the pointer lock will be activated and the compositor + * sends a locked event. + * + * The protocol provides no guarantee that the constraints are ever + * satisfied, and does not require the compositor to send an error if the + * constraints cannot ever be satisfied. It is thus possible to request a + * lock that will never activate. + * + * There may not be another pointer constraint of any kind requested or + * active on the surface for any of the wl_pointer objects of the seat of + * the passed pointer when requesting a lock. If there is, an error will be + * raised. See general pointer lock documentation for more details. + * + * The intersection of the region passed with this request and the input + * region of the surface is used to determine where the pointer must be + * in order for the lock to activate. It is up to the compositor whether to + * warp the pointer or require some kind of user interaction for the lock + * to activate. If the region is null the surface input region is used. + * + * A surface may receive pointer focus without the lock being activated. + * + * The request creates a new object wp_locked_pointer which is used to + * interact with the lock as well as receive updates about its state. See + * the the description of wp_locked_pointer for further information. + * + * Note that while a pointer is locked, the wl_pointer objects of the + * corresponding seat will not emit any wl_pointer.motion events, but + * relative motion events will still be emitted via wp_relative_pointer + * objects of the same seat. wl_pointer.axis and wl_pointer.button events + * are unaffected. + */ +static inline struct zwp_locked_pointer_v1 * +zwp_pointer_constraints_v1_lock_pointer(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, struct wl_surface *surface, struct wl_pointer *pointer, struct wl_region *region, uint32_t lifetime) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_pointer_constraints_v1, + ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER, &zwp_locked_pointer_v1_interface, NULL, surface, pointer, region, lifetime); + + return (struct zwp_locked_pointer_v1 *) id; +} + +/** + * @ingroup iface_zwp_pointer_constraints_v1 + * + * The confine_pointer request lets the client request to confine the + * pointer cursor to a given region. This request may not take effect + * immediately; in the future, when the compositor deems implementation- + * specific constraints are satisfied, the pointer confinement will be + * activated and the compositor sends a confined event. + * + * The intersection of the region passed with this request and the input + * region of the surface is used to determine where the pointer must be + * in order for the confinement to activate. It is up to the compositor + * whether to warp the pointer or require some kind of user interaction for + * the confinement to activate. If the region is null the surface input + * region is used. + * + * The request will create a new object wp_confined_pointer which is used + * to interact with the confinement as well as receive updates about its + * state. See the the description of wp_confined_pointer for further + * information. + */ +static inline struct zwp_confined_pointer_v1 * +zwp_pointer_constraints_v1_confine_pointer(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, struct wl_surface *surface, struct wl_pointer *pointer, struct wl_region *region, uint32_t lifetime) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_pointer_constraints_v1, + ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER, &zwp_confined_pointer_v1_interface, NULL, surface, pointer, region, lifetime); + + return (struct zwp_confined_pointer_v1 *) id; +} + +/** + * @ingroup iface_zwp_locked_pointer_v1 + * @struct zwp_locked_pointer_v1_listener + */ +struct zwp_locked_pointer_v1_listener { + /** + * lock activation event + * + * Notification that the pointer lock of the seat's pointer is + * activated. + */ + void (*locked)(void *data, + struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1); + /** + * lock deactivation event + * + * Notification that the pointer lock of the seat's pointer is no + * longer active. If this is a oneshot pointer lock (see + * wp_pointer_constraints.lifetime) this object is now defunct and + * should be destroyed. If this is a persistent pointer lock (see + * wp_pointer_constraints.lifetime) this pointer lock may again + * reactivate in the future. + */ + void (*unlocked)(void *data, + struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1); +}; + +/** + * @ingroup iface_zwp_locked_pointer_v1 + */ +static inline int +zwp_locked_pointer_v1_add_listener(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, + const struct zwp_locked_pointer_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_locked_pointer_v1, + (void (**)(void)) listener, data); +} + +#define ZWP_LOCKED_POINTER_V1_DESTROY 0 +#define ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT 1 +#define ZWP_LOCKED_POINTER_V1_SET_REGION 2 + +/** + * @ingroup iface_zwp_locked_pointer_v1 + */ +#define ZWP_LOCKED_POINTER_V1_LOCKED_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_locked_pointer_v1 + */ +#define ZWP_LOCKED_POINTER_V1_UNLOCKED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_locked_pointer_v1 + */ +#define ZWP_LOCKED_POINTER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_locked_pointer_v1 + */ +#define ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_locked_pointer_v1 + */ +#define ZWP_LOCKED_POINTER_V1_SET_REGION_SINCE_VERSION 1 + +/** @ingroup iface_zwp_locked_pointer_v1 */ +static inline void +zwp_locked_pointer_v1_set_user_data(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_locked_pointer_v1, user_data); +} + +/** @ingroup iface_zwp_locked_pointer_v1 */ +static inline void * +zwp_locked_pointer_v1_get_user_data(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_locked_pointer_v1); +} + +static inline uint32_t +zwp_locked_pointer_v1_get_version(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_locked_pointer_v1); +} + +/** + * @ingroup iface_zwp_locked_pointer_v1 + * + * Destroy the locked pointer object. If applicable, the compositor will + * unlock the pointer. + */ +static inline void +zwp_locked_pointer_v1_destroy(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1) +{ + wl_proxy_marshal((struct wl_proxy *) zwp_locked_pointer_v1, + ZWP_LOCKED_POINTER_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwp_locked_pointer_v1); +} + +/** + * @ingroup iface_zwp_locked_pointer_v1 + * + * Set the cursor position hint relative to the top left corner of the + * surface. + * + * If the client is drawing its own cursor, it should update the position + * hint to the position of its own cursor. A compositor may use this + * information to warp the pointer upon unlock in order to avoid pointer + * jumps. + * + * The cursor position hint is double buffered. The new hint will only take + * effect when the associated surface gets it pending state applied. See + * wl_surface.commit for details. + */ +static inline void +zwp_locked_pointer_v1_set_cursor_position_hint(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, wl_fixed_t surface_x, wl_fixed_t surface_y) +{ + wl_proxy_marshal((struct wl_proxy *) zwp_locked_pointer_v1, + ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT, surface_x, surface_y); +} + +/** + * @ingroup iface_zwp_locked_pointer_v1 + * + * Set a new region used to lock the pointer. + * + * The new lock region is double-buffered. The new lock region will + * only take effect when the associated surface gets its pending state + * applied. See wl_surface.commit for details. + * + * For details about the lock region, see wp_locked_pointer. + */ +static inline void +zwp_locked_pointer_v1_set_region(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, struct wl_region *region) +{ + wl_proxy_marshal((struct wl_proxy *) zwp_locked_pointer_v1, + ZWP_LOCKED_POINTER_V1_SET_REGION, region); +} + +/** + * @ingroup iface_zwp_confined_pointer_v1 + * @struct zwp_confined_pointer_v1_listener + */ +struct zwp_confined_pointer_v1_listener { + /** + * pointer confined + * + * Notification that the pointer confinement of the seat's + * pointer is activated. + */ + void (*confined)(void *data, + struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1); + /** + * pointer unconfined + * + * Notification that the pointer confinement of the seat's + * pointer is no longer active. If this is a oneshot pointer + * confinement (see wp_pointer_constraints.lifetime) this object is + * now defunct and should be destroyed. If this is a persistent + * pointer confinement (see wp_pointer_constraints.lifetime) this + * pointer confinement may again reactivate in the future. + */ + void (*unconfined)(void *data, + struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1); +}; + +/** + * @ingroup iface_zwp_confined_pointer_v1 + */ +static inline int +zwp_confined_pointer_v1_add_listener(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1, + const struct zwp_confined_pointer_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_confined_pointer_v1, + (void (**)(void)) listener, data); +} + +#define ZWP_CONFINED_POINTER_V1_DESTROY 0 +#define ZWP_CONFINED_POINTER_V1_SET_REGION 1 + +/** + * @ingroup iface_zwp_confined_pointer_v1 + */ +#define ZWP_CONFINED_POINTER_V1_CONFINED_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_confined_pointer_v1 + */ +#define ZWP_CONFINED_POINTER_V1_UNCONFINED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_confined_pointer_v1 + */ +#define ZWP_CONFINED_POINTER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_confined_pointer_v1 + */ +#define ZWP_CONFINED_POINTER_V1_SET_REGION_SINCE_VERSION 1 + +/** @ingroup iface_zwp_confined_pointer_v1 */ +static inline void +zwp_confined_pointer_v1_set_user_data(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_confined_pointer_v1, user_data); +} + +/** @ingroup iface_zwp_confined_pointer_v1 */ +static inline void * +zwp_confined_pointer_v1_get_user_data(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_confined_pointer_v1); +} + +static inline uint32_t +zwp_confined_pointer_v1_get_version(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_confined_pointer_v1); +} + +/** + * @ingroup iface_zwp_confined_pointer_v1 + * + * Destroy the confined pointer object. If applicable, the compositor will + * unconfine the pointer. + */ +static inline void +zwp_confined_pointer_v1_destroy(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1) +{ + wl_proxy_marshal((struct wl_proxy *) zwp_confined_pointer_v1, + ZWP_CONFINED_POINTER_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwp_confined_pointer_v1); +} + +/** + * @ingroup iface_zwp_confined_pointer_v1 + * + * Set a new region used to confine the pointer. + * + * The new confine region is double-buffered. The new confine region will + * only take effect when the associated surface gets its pending state + * applied. See wl_surface.commit for details. + * + * If the confinement is active when the new confinement region is applied + * and the pointer ends up outside of newly applied region, the pointer may + * warped to a position within the new confinement region. If warped, a + * wl_pointer.motion event will be emitted, but no + * wp_relative_pointer.relative_motion event. + * + * The compositor may also, instead of using the new region, unconfine the + * pointer. + * + * For details about the confine region, see wp_confined_pointer. + */ +static inline void +zwp_confined_pointer_v1_set_region(struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1, struct wl_region *region) +{ + wl_proxy_marshal((struct wl_proxy *) zwp_confined_pointer_v1, + ZWP_CONFINED_POINTER_V1_SET_REGION, region); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c new file mode 100644 index 0000000..cb8946b --- /dev/null +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.c @@ -0,0 +1,79 @@ +/* Generated by wayland-scanner */ + +/* + * Copyright © 2014 Jonas Ådahl + * Copyright © 2015 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_pointer_interface; +extern const struct wl_interface zwp_relative_pointer_v1_interface; + +static const struct wl_interface *relative_pointer_unstable_v1_types[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &zwp_relative_pointer_v1_interface, + &wl_pointer_interface, +}; + +static const struct wl_message zwp_relative_pointer_manager_v1_requests[] = { + { "destroy", "", relative_pointer_unstable_v1_types + 0 }, + { "get_relative_pointer", "no", relative_pointer_unstable_v1_types + 6 }, +}; + +WL_PRIVATE const struct wl_interface zwp_relative_pointer_manager_v1_interface = { + "zwp_relative_pointer_manager_v1", 1, + 2, zwp_relative_pointer_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message zwp_relative_pointer_v1_requests[] = { + { "destroy", "", relative_pointer_unstable_v1_types + 0 }, +}; + +static const struct wl_message zwp_relative_pointer_v1_events[] = { + { "relative_motion", "uuffff", relative_pointer_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwp_relative_pointer_v1_interface = { + "zwp_relative_pointer_v1", 1, + 1, zwp_relative_pointer_v1_requests, + 1, zwp_relative_pointer_v1_events, +}; + diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.h b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.h new file mode 100644 index 0000000..ead5e5d --- /dev/null +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-relative-pointer-unstable-v1-client-protocol.h @@ -0,0 +1,295 @@ +/* Generated by wayland-scanner */ + +#ifndef RELATIVE_POINTER_UNSTABLE_V1_CLIENT_PROTOCOL_H +#define RELATIVE_POINTER_UNSTABLE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_relative_pointer_unstable_v1 The relative_pointer_unstable_v1 protocol + * protocol for relative pointer motion events + * + * @section page_desc_relative_pointer_unstable_v1 Description + * + * This protocol specifies a set of interfaces used for making clients able to + * receive relative pointer events not obstructed by barriers (such as the + * monitor edge or other pointer barriers). + * + * To start receiving relative pointer events, a client must first bind the + * global interface "wp_relative_pointer_manager" which, if a compositor + * supports relative pointer motion events, is exposed by the registry. After + * having created the relative pointer manager proxy object, the client uses + * it to create the actual relative pointer object using the + * "get_relative_pointer" request given a wl_pointer. The relative pointer + * motion events will then, when applicable, be transmitted via the proxy of + * the newly created relative pointer object. See the documentation of the + * relative pointer interface for more details. + * + * Warning! The protocol described in this file is experimental and backward + * incompatible changes may be made. Backward compatible changes may be added + * together with the corresponding interface version bump. Backward + * incompatible changes are done by bumping the version number in the protocol + * and interface names and resetting the interface version. Once the protocol + * is to be declared stable, the 'z' prefix and the version number in the + * protocol and interface names are removed and the interface version number is + * reset. + * + * @section page_ifaces_relative_pointer_unstable_v1 Interfaces + * - @subpage page_iface_zwp_relative_pointer_manager_v1 - get relative pointer objects + * - @subpage page_iface_zwp_relative_pointer_v1 - relative pointer object + * @section page_copyright_relative_pointer_unstable_v1 Copyright + *
+ *
+ * Copyright © 2014      Jonas Ådahl
+ * Copyright © 2015      Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_pointer; +struct zwp_relative_pointer_manager_v1; +struct zwp_relative_pointer_v1; + +/** + * @page page_iface_zwp_relative_pointer_manager_v1 zwp_relative_pointer_manager_v1 + * @section page_iface_zwp_relative_pointer_manager_v1_desc Description + * + * A global interface used for getting the relative pointer object for a + * given pointer. + * @section page_iface_zwp_relative_pointer_manager_v1_api API + * See @ref iface_zwp_relative_pointer_manager_v1. + */ +/** + * @defgroup iface_zwp_relative_pointer_manager_v1 The zwp_relative_pointer_manager_v1 interface + * + * A global interface used for getting the relative pointer object for a + * given pointer. + */ +extern const struct wl_interface zwp_relative_pointer_manager_v1_interface; +/** + * @page page_iface_zwp_relative_pointer_v1 zwp_relative_pointer_v1 + * @section page_iface_zwp_relative_pointer_v1_desc Description + * + * A wp_relative_pointer object is an extension to the wl_pointer interface + * used for emitting relative pointer events. It shares the same focus as + * wl_pointer objects of the same seat and will only emit events when it has + * focus. + * @section page_iface_zwp_relative_pointer_v1_api API + * See @ref iface_zwp_relative_pointer_v1. + */ +/** + * @defgroup iface_zwp_relative_pointer_v1 The zwp_relative_pointer_v1 interface + * + * A wp_relative_pointer object is an extension to the wl_pointer interface + * used for emitting relative pointer events. It shares the same focus as + * wl_pointer objects of the same seat and will only emit events when it has + * focus. + */ +extern const struct wl_interface zwp_relative_pointer_v1_interface; + +#define ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY 0 +#define ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER 1 + + +/** + * @ingroup iface_zwp_relative_pointer_manager_v1 + */ +#define ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zwp_relative_pointer_manager_v1 + */ +#define ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER_SINCE_VERSION 1 + +/** @ingroup iface_zwp_relative_pointer_manager_v1 */ +static inline void +zwp_relative_pointer_manager_v1_set_user_data(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_relative_pointer_manager_v1, user_data); +} + +/** @ingroup iface_zwp_relative_pointer_manager_v1 */ +static inline void * +zwp_relative_pointer_manager_v1_get_user_data(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_relative_pointer_manager_v1); +} + +static inline uint32_t +zwp_relative_pointer_manager_v1_get_version(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_manager_v1); +} + +/** + * @ingroup iface_zwp_relative_pointer_manager_v1 + * + * Used by the client to notify the server that it will no longer use this + * relative pointer manager object. + */ +static inline void +zwp_relative_pointer_manager_v1_destroy(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1) +{ + wl_proxy_marshal((struct wl_proxy *) zwp_relative_pointer_manager_v1, + ZWP_RELATIVE_POINTER_MANAGER_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwp_relative_pointer_manager_v1); +} + +/** + * @ingroup iface_zwp_relative_pointer_manager_v1 + * + * Create a relative pointer interface given a wl_pointer object. See the + * wp_relative_pointer interface for more details. + */ +static inline struct zwp_relative_pointer_v1 * +zwp_relative_pointer_manager_v1_get_relative_pointer(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1, struct wl_pointer *pointer) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) zwp_relative_pointer_manager_v1, + ZWP_RELATIVE_POINTER_MANAGER_V1_GET_RELATIVE_POINTER, &zwp_relative_pointer_v1_interface, NULL, pointer); + + return (struct zwp_relative_pointer_v1 *) id; +} + +/** + * @ingroup iface_zwp_relative_pointer_v1 + * @struct zwp_relative_pointer_v1_listener + */ +struct zwp_relative_pointer_v1_listener { + /** + * relative pointer motion + * + * Relative x/y pointer motion from the pointer of the seat + * associated with this object. + * + * A relative motion is in the same dimension as regular wl_pointer + * motion events, except they do not represent an absolute + * position. For example, moving a pointer from (x, y) to (x', y') + * would have the equivalent relative motion (x' - x, y' - y). If a + * pointer motion caused the absolute pointer position to be + * clipped by for example the edge of the monitor, the relative + * motion is unaffected by the clipping and will represent the + * unclipped motion. + * + * This event also contains non-accelerated motion deltas. The + * non-accelerated delta is, when applicable, the regular pointer + * motion delta as it was before having applied motion acceleration + * and other transformations such as normalization. + * + * Note that the non-accelerated delta does not represent 'raw' + * events as they were read from some device. Pointer motion + * acceleration is device- and configuration-specific and + * non-accelerated deltas and accelerated deltas may have the same + * value on some devices. + * + * Relative motions are not coupled to wl_pointer.motion events, + * and can be sent in combination with such events, but also + * independently. There may also be scenarios where + * wl_pointer.motion is sent, but there is no relative motion. The + * order of an absolute and relative motion event originating from + * the same physical motion is not guaranteed. + * + * If the client needs button events or focus state, it can receive + * them from a wl_pointer object of the same seat that the + * wp_relative_pointer object is associated with. + * @param utime_hi high 32 bits of a 64 bit timestamp with microsecond granularity + * @param utime_lo low 32 bits of a 64 bit timestamp with microsecond granularity + * @param dx the x component of the motion vector + * @param dy the y component of the motion vector + * @param dx_unaccel the x component of the unaccelerated motion vector + * @param dy_unaccel the y component of the unaccelerated motion vector + */ + void (*relative_motion)(void *data, + struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1, + uint32_t utime_hi, + uint32_t utime_lo, + wl_fixed_t dx, + wl_fixed_t dy, + wl_fixed_t dx_unaccel, + wl_fixed_t dy_unaccel); +}; + +/** + * @ingroup iface_zwp_relative_pointer_v1 + */ +static inline int +zwp_relative_pointer_v1_add_listener(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1, + const struct zwp_relative_pointer_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zwp_relative_pointer_v1, + (void (**)(void)) listener, data); +} + +#define ZWP_RELATIVE_POINTER_V1_DESTROY 0 + +/** + * @ingroup iface_zwp_relative_pointer_v1 + */ +#define ZWP_RELATIVE_POINTER_V1_RELATIVE_MOTION_SINCE_VERSION 1 + +/** + * @ingroup iface_zwp_relative_pointer_v1 + */ +#define ZWP_RELATIVE_POINTER_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwp_relative_pointer_v1 */ +static inline void +zwp_relative_pointer_v1_set_user_data(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zwp_relative_pointer_v1, user_data); +} + +/** @ingroup iface_zwp_relative_pointer_v1 */ +static inline void * +zwp_relative_pointer_v1_get_user_data(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zwp_relative_pointer_v1); +} + +static inline uint32_t +zwp_relative_pointer_v1_get_version(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zwp_relative_pointer_v1); +} + +/** + * @ingroup iface_zwp_relative_pointer_v1 + */ +static inline void +zwp_relative_pointer_v1_destroy(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1) +{ + wl_proxy_marshal((struct wl_proxy *) zwp_relative_pointer_v1, + ZWP_RELATIVE_POINTER_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zwp_relative_pointer_v1); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-viewporter-client-protocol.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-viewporter-client-protocol.c new file mode 100644 index 0000000..9526e83 --- /dev/null +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-viewporter-client-protocol.c @@ -0,0 +1,74 @@ +/* Generated by wayland-scanner */ + +/* + * Copyright © 2013-2016 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wp_viewport_interface; + +static const struct wl_interface *viewporter_types[] = { + NULL, + NULL, + NULL, + NULL, + &wp_viewport_interface, + &wl_surface_interface, +}; + +static const struct wl_message wp_viewporter_requests[] = { + { "destroy", "", viewporter_types + 0 }, + { "get_viewport", "no", viewporter_types + 4 }, +}; + +WL_PRIVATE const struct wl_interface wp_viewporter_interface = { + "wp_viewporter", 1, + 2, wp_viewporter_requests, + 0, NULL, +}; + +static const struct wl_message wp_viewport_requests[] = { + { "destroy", "", viewporter_types + 0 }, + { "set_source", "ffff", viewporter_types + 0 }, + { "set_destination", "ii", viewporter_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_viewport_interface = { + "wp_viewport", 1, + 3, wp_viewport_requests, + 0, NULL, +}; + diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-viewporter-client-protocol.h b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-viewporter-client-protocol.h new file mode 100644 index 0000000..bade25a --- /dev/null +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-viewporter-client-protocol.h @@ -0,0 +1,408 @@ +/* Generated by wayland-scanner */ + +#ifndef VIEWPORTER_CLIENT_PROTOCOL_H +#define VIEWPORTER_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_viewporter The viewporter protocol + * @section page_ifaces_viewporter Interfaces + * - @subpage page_iface_wp_viewporter - surface cropping and scaling + * - @subpage page_iface_wp_viewport - crop and scale interface to a wl_surface + * @section page_copyright_viewporter Copyright + *
+ *
+ * Copyright © 2013-2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_surface; +struct wp_viewport; +struct wp_viewporter; + +/** + * @page page_iface_wp_viewporter wp_viewporter + * @section page_iface_wp_viewporter_desc Description + * + * The global interface exposing surface cropping and scaling + * capabilities is used to instantiate an interface extension for a + * wl_surface object. This extended interface will then allow + * cropping and scaling the surface contents, effectively + * disconnecting the direct relationship between the buffer and the + * surface size. + * @section page_iface_wp_viewporter_api API + * See @ref iface_wp_viewporter. + */ +/** + * @defgroup iface_wp_viewporter The wp_viewporter interface + * + * The global interface exposing surface cropping and scaling + * capabilities is used to instantiate an interface extension for a + * wl_surface object. This extended interface will then allow + * cropping and scaling the surface contents, effectively + * disconnecting the direct relationship between the buffer and the + * surface size. + */ +extern const struct wl_interface wp_viewporter_interface; +/** + * @page page_iface_wp_viewport wp_viewport + * @section page_iface_wp_viewport_desc Description + * + * An additional interface to a wl_surface object, which allows the + * client to specify the cropping and scaling of the surface + * contents. + * + * This interface works with two concepts: the source rectangle (src_x, + * src_y, src_width, src_height), and the destination size (dst_width, + * dst_height). The contents of the source rectangle are scaled to the + * destination size, and content outside the source rectangle is ignored. + * This state is double-buffered, and is applied on the next + * wl_surface.commit. + * + * The two parts of crop and scale state are independent: the source + * rectangle, and the destination size. Initially both are unset, that + * is, no scaling is applied. The whole of the current wl_buffer is + * used as the source, and the surface size is as defined in + * wl_surface.attach. + * + * If the destination size is set, it causes the surface size to become + * dst_width, dst_height. The source (rectangle) is scaled to exactly + * this size. This overrides whatever the attached wl_buffer size is, + * unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface + * has no content and therefore no size. Otherwise, the size is always + * at least 1x1 in surface local coordinates. + * + * If the source rectangle is set, it defines what area of the wl_buffer is + * taken as the source. If the source rectangle is set and the destination + * size is not set, then src_width and src_height must be integers, and the + * surface size becomes the source rectangle size. This results in cropping + * without scaling. If src_width or src_height are not integers and + * destination size is not set, the bad_size protocol error is raised when + * the surface state is applied. + * + * The coordinate transformations from buffer pixel coordinates up to + * the surface-local coordinates happen in the following order: + * 1. buffer_transform (wl_surface.set_buffer_transform) + * 2. buffer_scale (wl_surface.set_buffer_scale) + * 3. crop and scale (wp_viewport.set*) + * This means, that the source rectangle coordinates of crop and scale + * are given in the coordinates after the buffer transform and scale, + * i.e. in the coordinates that would be the surface-local coordinates + * if the crop and scale was not applied. + * + * If src_x or src_y are negative, the bad_value protocol error is raised. + * Otherwise, if the source rectangle is partially or completely outside of + * the non-NULL wl_buffer, then the out_of_buffer protocol error is raised + * when the surface state is applied. A NULL wl_buffer does not raise the + * out_of_buffer error. + * + * The x, y arguments of wl_surface.attach are applied as normal to + * the surface. They indicate how many pixels to remove from the + * surface size from the left and the top. In other words, they are + * still in the surface-local coordinate system, just like dst_width + * and dst_height are. + * + * If the wl_surface associated with the wp_viewport is destroyed, + * all wp_viewport requests except 'destroy' raise the protocol error + * no_surface. + * + * If the wp_viewport object is destroyed, the crop and scale + * state is removed from the wl_surface. The change will be applied + * on the next wl_surface.commit. + * @section page_iface_wp_viewport_api API + * See @ref iface_wp_viewport. + */ +/** + * @defgroup iface_wp_viewport The wp_viewport interface + * + * An additional interface to a wl_surface object, which allows the + * client to specify the cropping and scaling of the surface + * contents. + * + * This interface works with two concepts: the source rectangle (src_x, + * src_y, src_width, src_height), and the destination size (dst_width, + * dst_height). The contents of the source rectangle are scaled to the + * destination size, and content outside the source rectangle is ignored. + * This state is double-buffered, and is applied on the next + * wl_surface.commit. + * + * The two parts of crop and scale state are independent: the source + * rectangle, and the destination size. Initially both are unset, that + * is, no scaling is applied. The whole of the current wl_buffer is + * used as the source, and the surface size is as defined in + * wl_surface.attach. + * + * If the destination size is set, it causes the surface size to become + * dst_width, dst_height. The source (rectangle) is scaled to exactly + * this size. This overrides whatever the attached wl_buffer size is, + * unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface + * has no content and therefore no size. Otherwise, the size is always + * at least 1x1 in surface local coordinates. + * + * If the source rectangle is set, it defines what area of the wl_buffer is + * taken as the source. If the source rectangle is set and the destination + * size is not set, then src_width and src_height must be integers, and the + * surface size becomes the source rectangle size. This results in cropping + * without scaling. If src_width or src_height are not integers and + * destination size is not set, the bad_size protocol error is raised when + * the surface state is applied. + * + * The coordinate transformations from buffer pixel coordinates up to + * the surface-local coordinates happen in the following order: + * 1. buffer_transform (wl_surface.set_buffer_transform) + * 2. buffer_scale (wl_surface.set_buffer_scale) + * 3. crop and scale (wp_viewport.set*) + * This means, that the source rectangle coordinates of crop and scale + * are given in the coordinates after the buffer transform and scale, + * i.e. in the coordinates that would be the surface-local coordinates + * if the crop and scale was not applied. + * + * If src_x or src_y are negative, the bad_value protocol error is raised. + * Otherwise, if the source rectangle is partially or completely outside of + * the non-NULL wl_buffer, then the out_of_buffer protocol error is raised + * when the surface state is applied. A NULL wl_buffer does not raise the + * out_of_buffer error. + * + * The x, y arguments of wl_surface.attach are applied as normal to + * the surface. They indicate how many pixels to remove from the + * surface size from the left and the top. In other words, they are + * still in the surface-local coordinate system, just like dst_width + * and dst_height are. + * + * If the wl_surface associated with the wp_viewport is destroyed, + * all wp_viewport requests except 'destroy' raise the protocol error + * no_surface. + * + * If the wp_viewport object is destroyed, the crop and scale + * state is removed from the wl_surface. The change will be applied + * on the next wl_surface.commit. + */ +extern const struct wl_interface wp_viewport_interface; + +#ifndef WP_VIEWPORTER_ERROR_ENUM +#define WP_VIEWPORTER_ERROR_ENUM +enum wp_viewporter_error { + /** + * the surface already has a viewport object associated + */ + WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS = 0, +}; +#endif /* WP_VIEWPORTER_ERROR_ENUM */ + +#define WP_VIEWPORTER_DESTROY 0 +#define WP_VIEWPORTER_GET_VIEWPORT 1 + + +/** + * @ingroup iface_wp_viewporter + */ +#define WP_VIEWPORTER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_viewporter + */ +#define WP_VIEWPORTER_GET_VIEWPORT_SINCE_VERSION 1 + +/** @ingroup iface_wp_viewporter */ +static inline void +wp_viewporter_set_user_data(struct wp_viewporter *wp_viewporter, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_viewporter, user_data); +} + +/** @ingroup iface_wp_viewporter */ +static inline void * +wp_viewporter_get_user_data(struct wp_viewporter *wp_viewporter) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_viewporter); +} + +static inline uint32_t +wp_viewporter_get_version(struct wp_viewporter *wp_viewporter) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_viewporter); +} + +/** + * @ingroup iface_wp_viewporter + * + * Informs the server that the client will not be using this + * protocol object anymore. This does not affect any other objects, + * wp_viewport objects included. + */ +static inline void +wp_viewporter_destroy(struct wp_viewporter *wp_viewporter) +{ + wl_proxy_marshal((struct wl_proxy *) wp_viewporter, + WP_VIEWPORTER_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) wp_viewporter); +} + +/** + * @ingroup iface_wp_viewporter + * + * Instantiate an interface extension for the given wl_surface to + * crop and scale its content. If the given wl_surface already has + * a wp_viewport object associated, the viewport_exists + * protocol error is raised. + */ +static inline struct wp_viewport * +wp_viewporter_get_viewport(struct wp_viewporter *wp_viewporter, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) wp_viewporter, + WP_VIEWPORTER_GET_VIEWPORT, &wp_viewport_interface, NULL, surface); + + return (struct wp_viewport *) id; +} + +#ifndef WP_VIEWPORT_ERROR_ENUM +#define WP_VIEWPORT_ERROR_ENUM +enum wp_viewport_error { + /** + * negative or zero values in width or height + */ + WP_VIEWPORT_ERROR_BAD_VALUE = 0, + /** + * destination size is not integer + */ + WP_VIEWPORT_ERROR_BAD_SIZE = 1, + /** + * source rectangle extends outside of the content area + */ + WP_VIEWPORT_ERROR_OUT_OF_BUFFER = 2, + /** + * the wl_surface was destroyed + */ + WP_VIEWPORT_ERROR_NO_SURFACE = 3, +}; +#endif /* WP_VIEWPORT_ERROR_ENUM */ + +#define WP_VIEWPORT_DESTROY 0 +#define WP_VIEWPORT_SET_SOURCE 1 +#define WP_VIEWPORT_SET_DESTINATION 2 + + +/** + * @ingroup iface_wp_viewport + */ +#define WP_VIEWPORT_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_viewport + */ +#define WP_VIEWPORT_SET_SOURCE_SINCE_VERSION 1 +/** + * @ingroup iface_wp_viewport + */ +#define WP_VIEWPORT_SET_DESTINATION_SINCE_VERSION 1 + +/** @ingroup iface_wp_viewport */ +static inline void +wp_viewport_set_user_data(struct wp_viewport *wp_viewport, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_viewport, user_data); +} + +/** @ingroup iface_wp_viewport */ +static inline void * +wp_viewport_get_user_data(struct wp_viewport *wp_viewport) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_viewport); +} + +static inline uint32_t +wp_viewport_get_version(struct wp_viewport *wp_viewport) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_viewport); +} + +/** + * @ingroup iface_wp_viewport + * + * The associated wl_surface's crop and scale state is removed. + * The change is applied on the next wl_surface.commit. + */ +static inline void +wp_viewport_destroy(struct wp_viewport *wp_viewport) +{ + wl_proxy_marshal((struct wl_proxy *) wp_viewport, + WP_VIEWPORT_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) wp_viewport); +} + +/** + * @ingroup iface_wp_viewport + * + * Set the source rectangle of the associated wl_surface. See + * wp_viewport for the description, and relation to the wl_buffer + * size. + * + * If all of x, y, width and height are -1.0, the source rectangle is + * unset instead. Any other set of values where width or height are zero + * or negative, or x or y are negative, raise the bad_value protocol + * error. + * + * The crop and scale state is double-buffered state, and will be + * applied on the next wl_surface.commit. + */ +static inline void +wp_viewport_set_source(struct wp_viewport *wp_viewport, wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height) +{ + wl_proxy_marshal((struct wl_proxy *) wp_viewport, + WP_VIEWPORT_SET_SOURCE, x, y, width, height); +} + +/** + * @ingroup iface_wp_viewport + * + * Set the destination size of the associated wl_surface. See + * wp_viewport for the description, and relation to the wl_buffer + * size. + * + * If width is -1 and height is -1, the destination size is unset + * instead. Any other pair of values for width and height that + * contains zero or negative values raises the bad_value protocol + * error. + * + * The crop and scale state is double-buffered state, and will be + * applied on the next wl_surface.commit. + */ +static inline void +wp_viewport_set_destination(struct wp_viewport *wp_viewport, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) wp_viewport, + WP_VIEWPORT_SET_DESTINATION, width, height); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-xdg-decoration-unstable-v1-client-protocol.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-xdg-decoration-unstable-v1-client-protocol.c new file mode 100644 index 0000000..d8dbb2f --- /dev/null +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-xdg-decoration-unstable-v1-client-protocol.c @@ -0,0 +1,75 @@ +/* Generated by wayland-scanner */ + +/* + * Copyright © 2018 Simon Ser + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface xdg_toplevel_interface; +extern const struct wl_interface zxdg_toplevel_decoration_v1_interface; + +static const struct wl_interface *xdg_decoration_unstable_v1_types[] = { + NULL, + &zxdg_toplevel_decoration_v1_interface, + &xdg_toplevel_interface, +}; + +static const struct wl_message zxdg_decoration_manager_v1_requests[] = { + { "destroy", "", xdg_decoration_unstable_v1_types + 0 }, + { "get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1 }, +}; + +WL_PRIVATE const struct wl_interface zxdg_decoration_manager_v1_interface = { + "zxdg_decoration_manager_v1", 1, + 2, zxdg_decoration_manager_v1_requests, + 0, NULL, +}; + +static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = { + { "destroy", "", xdg_decoration_unstable_v1_types + 0 }, + { "set_mode", "u", xdg_decoration_unstable_v1_types + 0 }, + { "unset_mode", "", xdg_decoration_unstable_v1_types + 0 }, +}; + +static const struct wl_message zxdg_toplevel_decoration_v1_events[] = { + { "configure", "u", xdg_decoration_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zxdg_toplevel_decoration_v1_interface = { + "zxdg_toplevel_decoration_v1", 1, + 3, zxdg_toplevel_decoration_v1_requests, + 1, zxdg_toplevel_decoration_v1_events, +}; + diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-xdg-decoration-unstable-v1-client-protocol.h b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-xdg-decoration-unstable-v1-client-protocol.h new file mode 100644 index 0000000..6bd1bb3 --- /dev/null +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-xdg-decoration-unstable-v1-client-protocol.h @@ -0,0 +1,376 @@ +/* Generated by wayland-scanner */ + +#ifndef XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H +#define XDG_DECORATION_UNSTABLE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_xdg_decoration_unstable_v1 The xdg_decoration_unstable_v1 protocol + * @section page_ifaces_xdg_decoration_unstable_v1 Interfaces + * - @subpage page_iface_zxdg_decoration_manager_v1 - window decoration manager + * - @subpage page_iface_zxdg_toplevel_decoration_v1 - decoration object for a toplevel surface + * @section page_copyright_xdg_decoration_unstable_v1 Copyright + *
+ *
+ * Copyright © 2018 Simon Ser
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct xdg_toplevel; +struct zxdg_decoration_manager_v1; +struct zxdg_toplevel_decoration_v1; + +/** + * @page page_iface_zxdg_decoration_manager_v1 zxdg_decoration_manager_v1 + * @section page_iface_zxdg_decoration_manager_v1_desc Description + * + * This interface allows a compositor to announce support for server-side + * decorations. + * + * A window decoration is a set of window controls as deemed appropriate by + * the party managing them, such as user interface components used to move, + * resize and change a window's state. + * + * A client can use this protocol to request being decorated by a supporting + * compositor. + * + * If compositor and client do not negotiate the use of a server-side + * decoration using this protocol, clients continue to self-decorate as they + * see fit. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * interface version number is reset. + * @section page_iface_zxdg_decoration_manager_v1_api API + * See @ref iface_zxdg_decoration_manager_v1. + */ +/** + * @defgroup iface_zxdg_decoration_manager_v1 The zxdg_decoration_manager_v1 interface + * + * This interface allows a compositor to announce support for server-side + * decorations. + * + * A window decoration is a set of window controls as deemed appropriate by + * the party managing them, such as user interface components used to move, + * resize and change a window's state. + * + * A client can use this protocol to request being decorated by a supporting + * compositor. + * + * If compositor and client do not negotiate the use of a server-side + * decoration using this protocol, clients continue to self-decorate as they + * see fit. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * interface version number is reset. + */ +extern const struct wl_interface zxdg_decoration_manager_v1_interface; +/** + * @page page_iface_zxdg_toplevel_decoration_v1 zxdg_toplevel_decoration_v1 + * @section page_iface_zxdg_toplevel_decoration_v1_desc Description + * + * The decoration object allows the compositor to toggle server-side window + * decorations for a toplevel surface. The client can request to switch to + * another mode. + * + * The xdg_toplevel_decoration object must be destroyed before its + * xdg_toplevel. + * @section page_iface_zxdg_toplevel_decoration_v1_api API + * See @ref iface_zxdg_toplevel_decoration_v1. + */ +/** + * @defgroup iface_zxdg_toplevel_decoration_v1 The zxdg_toplevel_decoration_v1 interface + * + * The decoration object allows the compositor to toggle server-side window + * decorations for a toplevel surface. The client can request to switch to + * another mode. + * + * The xdg_toplevel_decoration object must be destroyed before its + * xdg_toplevel. + */ +extern const struct wl_interface zxdg_toplevel_decoration_v1_interface; + +#define ZXDG_DECORATION_MANAGER_V1_DESTROY 0 +#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION 1 + + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + */ +#define ZXDG_DECORATION_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_decoration_manager_v1 + */ +#define ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_decoration_manager_v1 */ +static inline void +zxdg_decoration_manager_v1_set_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_decoration_manager_v1, user_data); +} + +/** @ingroup iface_zxdg_decoration_manager_v1 */ +static inline void * +zxdg_decoration_manager_v1_get_user_data(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_decoration_manager_v1); +} + +static inline uint32_t +zxdg_decoration_manager_v1_get_version(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_decoration_manager_v1); +} + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + * + * Destroy the decoration manager. This doesn't destroy objects created + * with the manager. + */ +static inline void +zxdg_decoration_manager_v1_destroy(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1) +{ + wl_proxy_marshal((struct wl_proxy *) zxdg_decoration_manager_v1, + ZXDG_DECORATION_MANAGER_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zxdg_decoration_manager_v1); +} + +/** + * @ingroup iface_zxdg_decoration_manager_v1 + * + * Create a new decoration object associated with the given toplevel. + * + * Creating an xdg_toplevel_decoration from an xdg_toplevel which has a + * buffer attached or committed is a client error, and any attempts by a + * client to attach or manipulate a buffer prior to the first + * xdg_toplevel_decoration.configure event must also be treated as + * errors. + */ +static inline struct zxdg_toplevel_decoration_v1 * +zxdg_decoration_manager_v1_get_toplevel_decoration(struct zxdg_decoration_manager_v1 *zxdg_decoration_manager_v1, struct xdg_toplevel *toplevel) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) zxdg_decoration_manager_v1, + ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION, &zxdg_toplevel_decoration_v1_interface, NULL, toplevel); + + return (struct zxdg_toplevel_decoration_v1 *) id; +} + +#ifndef ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM +#define ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM +enum zxdg_toplevel_decoration_v1_error { + /** + * xdg_toplevel has a buffer attached before configure + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_UNCONFIGURED_BUFFER = 0, + /** + * xdg_toplevel already has a decoration object + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED = 1, + /** + * xdg_toplevel destroyed before the decoration object + */ + ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ORPHANED = 2, +}; +#endif /* ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ENUM */ + +#ifndef ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM +#define ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * window decoration modes + * + * These values describe window decoration modes. + */ +enum zxdg_toplevel_decoration_v1_mode { + /** + * no server-side window decoration + */ + ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE = 1, + /** + * server-side window decoration + */ + ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE = 2, +}; +#endif /* ZXDG_TOPLEVEL_DECORATION_V1_MODE_ENUM */ + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * @struct zxdg_toplevel_decoration_v1_listener + */ +struct zxdg_toplevel_decoration_v1_listener { + /** + * suggest a surface change + * + * The configure event asks the client to change its decoration + * mode. The configured state should not be applied immediately. + * Clients must send an ack_configure in response to this event. + * See xdg_surface.configure and xdg_surface.ack_configure for + * details. + * + * A configure event can be sent at any time. The specified mode + * must be obeyed by the client. + * @param mode the decoration mode + */ + void (*configure)(void *data, + struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, + uint32_t mode); +}; + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +static inline int +zxdg_toplevel_decoration_v1_add_listener(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, + const struct zxdg_toplevel_decoration_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) zxdg_toplevel_decoration_v1, + (void (**)(void)) listener, data); +} + +#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY 0 +#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE 1 +#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE 2 + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + */ +#define ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE_SINCE_VERSION 1 + +/** @ingroup iface_zxdg_toplevel_decoration_v1 */ +static inline void +zxdg_toplevel_decoration_v1_set_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1, user_data); +} + +/** @ingroup iface_zxdg_toplevel_decoration_v1 */ +static inline void * +zxdg_toplevel_decoration_v1_get_user_data(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) zxdg_toplevel_decoration_v1); +} + +static inline uint32_t +zxdg_toplevel_decoration_v1_get_version(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) zxdg_toplevel_decoration_v1); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Switch back to a mode without any server-side decorations at the next + * commit. + */ +static inline void +zxdg_toplevel_decoration_v1_destroy(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) zxdg_toplevel_decoration_v1); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Set the toplevel surface decoration mode. This informs the compositor + * that the client prefers the provided decoration mode. + * + * After requesting a decoration mode, the compositor will respond by + * emitting an xdg_surface.configure event. The client should then update + * its content, drawing it without decorations if the received mode is + * server-side decorations. The client must also acknowledge the configure + * when committing the new content (see xdg_surface.ack_configure). + * + * The compositor can decide not to use the client's mode and enforce a + * different mode instead. + * + * Clients whose decoration mode depend on the xdg_toplevel state may send + * a set_mode request in response to an xdg_surface.configure event and wait + * for the next xdg_surface.configure event to prevent unwanted state. + * Such clients are responsible for preventing configure loops and must + * make sure not to send multiple successive set_mode requests with the + * same decoration mode. + */ +static inline void +zxdg_toplevel_decoration_v1_set_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode) +{ + wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE, mode); +} + +/** + * @ingroup iface_zxdg_toplevel_decoration_v1 + * + * Unset the toplevel surface decoration mode. This informs the compositor + * that the client doesn't prefer a particular decoration mode. + * + * This request has the same semantics as set_mode. + */ +static inline void +zxdg_toplevel_decoration_v1_unset_mode(struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1) +{ + wl_proxy_marshal((struct wl_proxy *) zxdg_toplevel_decoration_v1, + ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-xdg-shell-client-protocol.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-xdg-shell-client-protocol.c new file mode 100644 index 0000000..9f8f0a5 --- /dev/null +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-xdg-shell-client-protocol.c @@ -0,0 +1,181 @@ +/* Generated by wayland-scanner */ + +/* + * Copyright © 2008-2013 Kristian Høgsberg + * Copyright © 2013 Rafael Antognolli + * Copyright © 2013 Jasper St. Pierre + * Copyright © 2010-2013 Intel Corporation + * Copyright © 2015-2017 Samsung Electronics Co., Ltd + * Copyright © 2015-2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wl_output_interface; +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface xdg_popup_interface; +extern const struct wl_interface xdg_positioner_interface; +extern const struct wl_interface xdg_surface_interface; +extern const struct wl_interface xdg_toplevel_interface; + +static const struct wl_interface *xdg_shell_types[] = { + NULL, + NULL, + NULL, + NULL, + &xdg_positioner_interface, + &xdg_surface_interface, + &wl_surface_interface, + &xdg_toplevel_interface, + &xdg_popup_interface, + &xdg_surface_interface, + &xdg_positioner_interface, + &xdg_toplevel_interface, + &wl_seat_interface, + NULL, + NULL, + NULL, + &wl_seat_interface, + NULL, + &wl_seat_interface, + NULL, + NULL, + &wl_output_interface, + &wl_seat_interface, + NULL, + &xdg_positioner_interface, + NULL, +}; + +static const struct wl_message xdg_wm_base_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "create_positioner", "n", xdg_shell_types + 4 }, + { "get_xdg_surface", "no", xdg_shell_types + 5 }, + { "pong", "u", xdg_shell_types + 0 }, +}; + +static const struct wl_message xdg_wm_base_events[] = { + { "ping", "u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_wm_base_interface = { + "xdg_wm_base", 3, + 4, xdg_wm_base_requests, + 1, xdg_wm_base_events, +}; + +static const struct wl_message xdg_positioner_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "set_size", "ii", xdg_shell_types + 0 }, + { "set_anchor_rect", "iiii", xdg_shell_types + 0 }, + { "set_anchor", "u", xdg_shell_types + 0 }, + { "set_gravity", "u", xdg_shell_types + 0 }, + { "set_constraint_adjustment", "u", xdg_shell_types + 0 }, + { "set_offset", "ii", xdg_shell_types + 0 }, + { "set_reactive", "3", xdg_shell_types + 0 }, + { "set_parent_size", "3ii", xdg_shell_types + 0 }, + { "set_parent_configure", "3u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_positioner_interface = { + "xdg_positioner", 3, + 10, xdg_positioner_requests, + 0, NULL, +}; + +static const struct wl_message xdg_surface_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "get_toplevel", "n", xdg_shell_types + 7 }, + { "get_popup", "n?oo", xdg_shell_types + 8 }, + { "set_window_geometry", "iiii", xdg_shell_types + 0 }, + { "ack_configure", "u", xdg_shell_types + 0 }, +}; + +static const struct wl_message xdg_surface_events[] = { + { "configure", "u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_surface_interface = { + "xdg_surface", 3, + 5, xdg_surface_requests, + 1, xdg_surface_events, +}; + +static const struct wl_message xdg_toplevel_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "set_parent", "?o", xdg_shell_types + 11 }, + { "set_title", "s", xdg_shell_types + 0 }, + { "set_app_id", "s", xdg_shell_types + 0 }, + { "show_window_menu", "ouii", xdg_shell_types + 12 }, + { "move", "ou", xdg_shell_types + 16 }, + { "resize", "ouu", xdg_shell_types + 18 }, + { "set_max_size", "ii", xdg_shell_types + 0 }, + { "set_min_size", "ii", xdg_shell_types + 0 }, + { "set_maximized", "", xdg_shell_types + 0 }, + { "unset_maximized", "", xdg_shell_types + 0 }, + { "set_fullscreen", "?o", xdg_shell_types + 21 }, + { "unset_fullscreen", "", xdg_shell_types + 0 }, + { "set_minimized", "", xdg_shell_types + 0 }, +}; + +static const struct wl_message xdg_toplevel_events[] = { + { "configure", "iia", xdg_shell_types + 0 }, + { "close", "", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_toplevel_interface = { + "xdg_toplevel", 3, + 14, xdg_toplevel_requests, + 2, xdg_toplevel_events, +}; + +static const struct wl_message xdg_popup_requests[] = { + { "destroy", "", xdg_shell_types + 0 }, + { "grab", "ou", xdg_shell_types + 22 }, + { "reposition", "3ou", xdg_shell_types + 24 }, +}; + +static const struct wl_message xdg_popup_events[] = { + { "configure", "iiii", xdg_shell_types + 0 }, + { "popup_done", "", xdg_shell_types + 0 }, + { "repositioned", "3u", xdg_shell_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface xdg_popup_interface = { + "xdg_popup", 3, + 3, xdg_popup_requests, + 3, xdg_popup_events, +}; + diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-xdg-shell-client-protocol.h b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-xdg-shell-client-protocol.h new file mode 100644 index 0000000..40baa88 --- /dev/null +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wayland-xdg-shell-client-protocol.h @@ -0,0 +1,1988 @@ +/* Generated by wayland-scanner */ + +#ifndef XDG_SHELL_CLIENT_PROTOCOL_H +#define XDG_SHELL_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_xdg_shell The xdg_shell protocol + * @section page_ifaces_xdg_shell Interfaces + * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces + * - @subpage page_iface_xdg_positioner - child surface positioner + * - @subpage page_iface_xdg_surface - desktop user interface surface base interface + * - @subpage page_iface_xdg_toplevel - toplevel surface + * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus + * @section page_copyright_xdg_shell Copyright + *
+ *
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013      Rafael Antognolli
+ * Copyright © 2013      Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2015-2017 Samsung Electronics Co., Ltd
+ * Copyright © 2015-2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_output; +struct wl_seat; +struct wl_surface; +struct xdg_popup; +struct xdg_positioner; +struct xdg_surface; +struct xdg_toplevel; +struct xdg_wm_base; + +/** + * @page page_iface_xdg_wm_base xdg_wm_base + * @section page_iface_xdg_wm_base_desc Description + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + * @section page_iface_xdg_wm_base_api API + * See @ref iface_xdg_wm_base. + */ +/** + * @defgroup iface_xdg_wm_base The xdg_wm_base interface + * + * The xdg_wm_base interface is exposed as a global object enabling clients + * to turn their wl_surfaces into windows in a desktop environment. It + * defines the basic functionality needed for clients and the compositor to + * create windows that can be dragged, resized, maximized, etc, as well as + * creating transient windows such as popup menus. + */ +extern const struct wl_interface xdg_wm_base_interface; +/** + * @page page_iface_xdg_positioner xdg_positioner + * @section page_iface_xdg_positioner_desc Description + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an error. + * @section page_iface_xdg_positioner_api API + * See @ref iface_xdg_positioner. + */ +/** + * @defgroup iface_xdg_positioner The xdg_positioner interface + * + * The xdg_positioner provides a collection of rules for the placement of a + * child surface relative to a parent surface. Rules can be defined to ensure + * the child surface remains within the visible area's borders, and to + * specify how the child surface changes its position, such as sliding along + * an axis, or flipping around a rectangle. These positioner-created rules are + * constrained by the requirement that a child surface must intersect with or + * be at least partially adjacent to its parent surface. + * + * See the various requests for details about possible rules. + * + * At the time of the request, the compositor makes a copy of the rules + * specified by the xdg_positioner. Thus, after the request is complete the + * xdg_positioner object can be destroyed or reused; further changes to the + * object will have no effect on previous usages. + * + * For an xdg_positioner object to be considered complete, it must have a + * non-zero size set by set_size, and a non-zero anchor rectangle set by + * set_anchor_rect. Passing an incomplete xdg_positioner object when + * positioning a surface raises an error. + */ +extern const struct wl_interface xdg_positioner_interface; +/** + * @page page_iface_xdg_surface xdg_surface + * @section page_iface_xdg_surface_desc Description + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * manipulate a buffer prior to the first xdg_surface.configure call must + * also be treated as errors. + * + * After creating a role-specific object and setting it up, the client must + * perform an initial commit without any buffer attached. The compositor + * will reply with an xdg_surface.configure event. The client must + * acknowledge it and is then allowed to attach a buffer to map the surface. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed. + * @section page_iface_xdg_surface_api API + * See @ref iface_xdg_surface. + */ +/** + * @defgroup iface_xdg_surface The xdg_surface interface + * + * An interface that may be implemented by a wl_surface, for + * implementations that provide a desktop-style user interface. + * + * It provides a base set of functionality required to construct user + * interface elements requiring management by the compositor, such as + * toplevel windows, menus, etc. The types of functionality are split into + * xdg_surface roles. + * + * Creating an xdg_surface does not set the role for a wl_surface. In order + * to map an xdg_surface, the client must create a role-specific object + * using, e.g., get_toplevel, get_popup. The wl_surface for any given + * xdg_surface can have at most one role, and may not be assigned any role + * not based on xdg_surface. + * + * A role must be assigned before any other requests are made to the + * xdg_surface object. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_surface state to take effect. + * + * Creating an xdg_surface from a wl_surface which has a buffer attached or + * committed is a client error, and any attempts by a client to attach or + * manipulate a buffer prior to the first xdg_surface.configure call must + * also be treated as errors. + * + * After creating a role-specific object and setting it up, the client must + * perform an initial commit without any buffer attached. The compositor + * will reply with an xdg_surface.configure event. The client must + * acknowledge it and is then allowed to attach a buffer to map the surface. + * + * Mapping an xdg_surface-based role surface is defined as making it + * possible for the surface to be shown by the compositor. Note that + * a mapped surface is not guaranteed to be visible once it is mapped. + * + * For an xdg_surface to be mapped by the compositor, the following + * conditions must be met: + * (1) the client has assigned an xdg_surface-based role to the surface + * (2) the client has set and committed the xdg_surface state and the + * role-dependent state to the surface + * (3) the client has committed a buffer to the surface + * + * A newly-unmapped surface is considered to have met condition (1) out + * of the 3 required conditions for mapping a surface if its role surface + * has not been destroyed. + */ +extern const struct wl_interface xdg_surface_interface; +/** + * @page page_iface_xdg_toplevel xdg_toplevel + * @section page_iface_xdg_toplevel_desc Description + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + * the state it had right after xdg_surface.get_toplevel. The client + * can re-map the toplevel by perfoming a commit without any buffer + * attached, waiting for a configure event and handling it as usual (see + * xdg_surface description). + * + * Attaching a null buffer to a toplevel unmaps the surface. + * @section page_iface_xdg_toplevel_api API + * See @ref iface_xdg_toplevel. + */ +/** + * @defgroup iface_xdg_toplevel The xdg_toplevel interface + * + * This interface defines an xdg_surface role which allows a surface to, + * among other things, set window-like properties such as maximize, + * fullscreen, and minimize, set application-specific metadata like title and + * id, and well as trigger user interactive operations such as interactive + * resize and move. + * + * Unmapping an xdg_toplevel means that the surface cannot be shown + * by the compositor until it is explicitly mapped again. + * All active operations (e.g., move, resize) are canceled and all + * attributes (e.g. title, state, stacking, ...) are discarded for + * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to + * the state it had right after xdg_surface.get_toplevel. The client + * can re-map the toplevel by perfoming a commit without any buffer + * attached, waiting for a configure event and handling it as usual (see + * xdg_surface description). + * + * Attaching a null buffer to a toplevel unmaps the surface. + */ +extern const struct wl_interface xdg_toplevel_interface; +/** + * @page page_iface_xdg_popup xdg_popup + * @section page_iface_xdg_popup_desc Description + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + * @section page_iface_xdg_popup_api API + * See @ref iface_xdg_popup. + */ +/** + * @defgroup iface_xdg_popup The xdg_popup interface + * + * A popup surface is a short-lived, temporary surface. It can be used to + * implement for example menus, popovers, tooltips and other similar user + * interface concepts. + * + * A popup can be made to take an explicit grab. See xdg_popup.grab for + * details. + * + * When the popup is dismissed, a popup_done event will be sent out, and at + * the same time the surface will be unmapped. See the xdg_popup.popup_done + * event for details. + * + * Explicitly destroying the xdg_popup object will also dismiss the popup and + * unmap the surface. Clients that want to dismiss the popup when another + * surface of their own is clicked should dismiss the popup using the destroy + * request. + * + * A newly created xdg_popup will be stacked on top of all previously created + * xdg_popup surfaces associated with the same xdg_toplevel. + * + * The parent of an xdg_popup must be mapped (see the xdg_surface + * description) before the xdg_popup itself. + * + * The client must call wl_surface.commit on the corresponding wl_surface + * for the xdg_popup state to take effect. + */ +extern const struct wl_interface xdg_popup_interface; + +#ifndef XDG_WM_BASE_ERROR_ENUM +#define XDG_WM_BASE_ERROR_ENUM +enum xdg_wm_base_error { + /** + * given wl_surface has another role + */ + XDG_WM_BASE_ERROR_ROLE = 0, + /** + * xdg_wm_base was destroyed before children + */ + XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1, + /** + * the client tried to map or destroy a non-topmost popup + */ + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2, + /** + * the client specified an invalid popup parent surface + */ + XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3, + /** + * the client provided an invalid surface state + */ + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4, + /** + * the client provided an invalid positioner + */ + XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5, +}; +#endif /* XDG_WM_BASE_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_wm_base + * @struct xdg_wm_base_listener + */ +struct xdg_wm_base_listener { + /** + * check if the client is alive + * + * The ping event asks the client if it's still alive. Pass the + * serial specified in the event back to the compositor by sending + * a "pong" request back with the specified serial. See + * xdg_wm_base.pong. + * + * Compositors can use this to determine if the client is still + * alive. It's unspecified what will happen if the client doesn't + * respond to the ping request, or in what timeframe. Clients + * should try to respond in a reasonable amount of time. + * + * A compositor is free to ping in any way it wants, but a client + * must always respond to any xdg_wm_base object it created. + * @param serial pass this to the pong request + */ + void (*ping)(void *data, + struct xdg_wm_base *xdg_wm_base, + uint32_t serial); +}; + +/** + * @ingroup iface_xdg_wm_base + */ +static inline int +xdg_wm_base_add_listener(struct xdg_wm_base *xdg_wm_base, + const struct xdg_wm_base_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_wm_base, + (void (**)(void)) listener, data); +} + +#define XDG_WM_BASE_DESTROY 0 +#define XDG_WM_BASE_CREATE_POSITIONER 1 +#define XDG_WM_BASE_GET_XDG_SURFACE 2 +#define XDG_WM_BASE_PONG 3 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PING_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_wm_base + */ +#define XDG_WM_BASE_PONG_SINCE_VERSION 1 + +/** @ingroup iface_xdg_wm_base */ +static inline void +xdg_wm_base_set_user_data(struct xdg_wm_base *xdg_wm_base, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_wm_base, user_data); +} + +/** @ingroup iface_xdg_wm_base */ +static inline void * +xdg_wm_base_get_user_data(struct xdg_wm_base *xdg_wm_base) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_wm_base); +} + +static inline uint32_t +xdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_wm_base); +} + +/** + * @ingroup iface_xdg_wm_base + * + * Destroy this xdg_wm_base object. + * + * Destroying a bound xdg_wm_base object while there are surfaces + * still alive created by this xdg_wm_base object instance is illegal + * and will result in a protocol error. + */ +static inline void +xdg_wm_base_destroy(struct xdg_wm_base *xdg_wm_base) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_wm_base); +} + +/** + * @ingroup iface_xdg_wm_base + * + * Create a positioner object. A positioner object is used to position + * surfaces relative to some parent surface. See the interface description + * and xdg_surface.get_popup for details. + */ +static inline struct xdg_positioner * +xdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_CREATE_POSITIONER, &xdg_positioner_interface, NULL); + + return (struct xdg_positioner *) id; +} + +/** + * @ingroup iface_xdg_wm_base + * + * This creates an xdg_surface for the given surface. While xdg_surface + * itself is not a role, the corresponding surface may only be assigned + * a role extending xdg_surface, such as xdg_toplevel or xdg_popup. + * + * This creates an xdg_surface for the given surface. An xdg_surface is + * used as basis to define a role to a given surface, such as xdg_toplevel + * or xdg_popup. It also manages functionality shared between xdg_surface + * based surface roles. + * + * See the documentation of xdg_surface for more details about what an + * xdg_surface is and how it is used. + */ +static inline struct xdg_surface * +xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_GET_XDG_SURFACE, &xdg_surface_interface, NULL, surface); + + return (struct xdg_surface *) id; +} + +/** + * @ingroup iface_xdg_wm_base + * + * A client must respond to a ping event with a pong request or + * the client may be deemed unresponsive. See xdg_wm_base.ping. + */ +static inline void +xdg_wm_base_pong(struct xdg_wm_base *xdg_wm_base, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_wm_base, + XDG_WM_BASE_PONG, serial); +} + +#ifndef XDG_POSITIONER_ERROR_ENUM +#define XDG_POSITIONER_ERROR_ENUM +enum xdg_positioner_error { + /** + * invalid input provided + */ + XDG_POSITIONER_ERROR_INVALID_INPUT = 0, +}; +#endif /* XDG_POSITIONER_ERROR_ENUM */ + +#ifndef XDG_POSITIONER_ANCHOR_ENUM +#define XDG_POSITIONER_ANCHOR_ENUM +enum xdg_positioner_anchor { + XDG_POSITIONER_ANCHOR_NONE = 0, + XDG_POSITIONER_ANCHOR_TOP = 1, + XDG_POSITIONER_ANCHOR_BOTTOM = 2, + XDG_POSITIONER_ANCHOR_LEFT = 3, + XDG_POSITIONER_ANCHOR_RIGHT = 4, + XDG_POSITIONER_ANCHOR_TOP_LEFT = 5, + XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6, + XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7, + XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8, +}; +#endif /* XDG_POSITIONER_ANCHOR_ENUM */ + +#ifndef XDG_POSITIONER_GRAVITY_ENUM +#define XDG_POSITIONER_GRAVITY_ENUM +enum xdg_positioner_gravity { + XDG_POSITIONER_GRAVITY_NONE = 0, + XDG_POSITIONER_GRAVITY_TOP = 1, + XDG_POSITIONER_GRAVITY_BOTTOM = 2, + XDG_POSITIONER_GRAVITY_LEFT = 3, + XDG_POSITIONER_GRAVITY_RIGHT = 4, + XDG_POSITIONER_GRAVITY_TOP_LEFT = 5, + XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6, + XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7, + XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8, +}; +#endif /* XDG_POSITIONER_GRAVITY_ENUM */ + +#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM +/** + * @ingroup iface_xdg_positioner + * vertically resize the surface + * + * Resize the surface vertically so that it is completely unconstrained. + */ +enum xdg_positioner_constraint_adjustment { + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16, + XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32, +}; +#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */ + +#define XDG_POSITIONER_DESTROY 0 +#define XDG_POSITIONER_SET_SIZE 1 +#define XDG_POSITIONER_SET_ANCHOR_RECT 2 +#define XDG_POSITIONER_SET_ANCHOR 3 +#define XDG_POSITIONER_SET_GRAVITY 4 +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT 5 +#define XDG_POSITIONER_SET_OFFSET 6 +#define XDG_POSITIONER_SET_REACTIVE 7 +#define XDG_POSITIONER_SET_PARENT_SIZE 8 +#define XDG_POSITIONER_SET_PARENT_CONFIGURE 9 + + +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_SIZE_SINCE_VERSION 3 +/** + * @ingroup iface_xdg_positioner + */ +#define XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION 3 + +/** @ingroup iface_xdg_positioner */ +static inline void +xdg_positioner_set_user_data(struct xdg_positioner *xdg_positioner, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_positioner, user_data); +} + +/** @ingroup iface_xdg_positioner */ +static inline void * +xdg_positioner_get_user_data(struct xdg_positioner *xdg_positioner) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_positioner); +} + +static inline uint32_t +xdg_positioner_get_version(struct xdg_positioner *xdg_positioner) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_positioner); +} + +/** + * @ingroup iface_xdg_positioner + * + * Notify the compositor that the xdg_positioner will no longer be used. + */ +static inline void +xdg_positioner_destroy(struct xdg_positioner *xdg_positioner) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_positioner); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the size of the surface that is to be positioned with the positioner + * object. The size is in surface-local coordinates and corresponds to the + * window geometry. See xdg_surface.set_window_geometry. + * + * If a zero or negative size is set the invalid_input error is raised. + */ +static inline void +xdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_SIZE, width, height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify the anchor rectangle within the parent surface that the child + * surface will be placed relative to. The rectangle is relative to the + * window geometry as defined by xdg_surface.set_window_geometry of the + * parent surface. + * + * When the xdg_positioner object is used to position a child surface, the + * anchor rectangle may not extend outside the window geometry of the + * positioned child's parent surface. + * + * If a negative size is set the invalid_input error is raised. + */ +static inline void +xdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_ANCHOR_RECT, x, y, width, height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Defines the anchor point for the anchor rectangle. The specified anchor + * is used derive an anchor point that the child surface will be + * positioned relative to. If a corner anchor is set (e.g. 'top_left' or + * 'bottom_right'), the anchor point will be at the specified corner; + * otherwise, the derived anchor point will be centered on the specified + * edge, or in the center of the anchor rectangle if no edge is specified. + */ +static inline void +xdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_ANCHOR, anchor); +} + +/** + * @ingroup iface_xdg_positioner + * + * Defines in what direction a surface should be positioned, relative to + * the anchor point of the parent surface. If a corner gravity is + * specified (e.g. 'bottom_right' or 'top_left'), then the child surface + * will be placed towards the specified gravity; otherwise, the child + * surface will be centered over the anchor point on any axis that had no + * gravity specified. + */ +static inline void +xdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravity) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_GRAVITY, gravity); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify how the window should be positioned if the originally intended + * position caused the surface to be constrained, meaning at least + * partially outside positioning boundaries set by the compositor. The + * adjustment is set by constructing a bitmask describing the adjustment to + * be made when the surface is constrained on that axis. + * + * If no bit for one axis is set, the compositor will assume that the child + * surface should not change its position on that axis when constrained. + * + * If more than one bit for one axis is set, the order of how adjustments + * are applied is specified in the corresponding adjustment descriptions. + * + * The default adjustment is none. + */ +static inline void +xdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, uint32_t constraint_adjustment) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT, constraint_adjustment); +} + +/** + * @ingroup iface_xdg_positioner + * + * Specify the surface position offset relative to the position of the + * anchor on the anchor rectangle and the anchor on the surface. For + * example if the anchor of the anchor rectangle is at (x, y), the surface + * has the gravity bottom|right, and the offset is (ox, oy), the calculated + * surface position will be (x + ox, y + oy). The offset position of the + * surface is the one used for constraint testing. See + * set_constraint_adjustment. + * + * An example use case is placing a popup menu on top of a user interface + * element, while aligning the user interface element of the parent surface + * with some user interface element placed somewhere in the popup surface. + */ +static inline void +xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_OFFSET, x, y); +} + +/** + * @ingroup iface_xdg_positioner + * + * When set reactive, the surface is reconstrained if the conditions used + * for constraining changed, e.g. the parent window moved. + * + * If the conditions changed and the popup was reconstrained, an + * xdg_popup.configure event is sent with updated geometry, followed by an + * xdg_surface.configure event. + */ +static inline void +xdg_positioner_set_reactive(struct xdg_positioner *xdg_positioner) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_REACTIVE); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the parent window geometry the compositor should use when + * positioning the popup. The compositor may use this information to + * determine the future state the popup should be constrained using. If + * this doesn't match the dimension of the parent the popup is eventually + * positioned against, the behavior is undefined. + * + * The arguments are given in the surface-local coordinate space. + */ +static inline void +xdg_positioner_set_parent_size(struct xdg_positioner *xdg_positioner, int32_t parent_width, int32_t parent_height) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_PARENT_SIZE, parent_width, parent_height); +} + +/** + * @ingroup iface_xdg_positioner + * + * Set the serial of an xdg_surface.configure event this positioner will be + * used in response to. The compositor may use this information together + * with set_parent_size to determine what future state the popup should be + * constrained using. + */ +static inline void +xdg_positioner_set_parent_configure(struct xdg_positioner *xdg_positioner, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_positioner, + XDG_POSITIONER_SET_PARENT_CONFIGURE, serial); +} + +#ifndef XDG_SURFACE_ERROR_ENUM +#define XDG_SURFACE_ERROR_ENUM +enum xdg_surface_error { + XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1, + XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2, + XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3, +}; +#endif /* XDG_SURFACE_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_surface + * @struct xdg_surface_listener + */ +struct xdg_surface_listener { + /** + * suggest a surface change + * + * The configure event marks the end of a configure sequence. A + * configure sequence is a set of one or more events configuring + * the state of the xdg_surface, including the final + * xdg_surface.configure event. + * + * Where applicable, xdg_surface surface roles will during a + * configure sequence extend this event as a latched state sent as + * events before the xdg_surface.configure event. Such events + * should be considered to make up a set of atomically applied + * configuration states, where the xdg_surface.configure commits + * the accumulated state. + * + * Clients should arrange their surface for the new states, and + * then send an ack_configure request with the serial sent in this + * configure event at some point before committing the new surface. + * + * If the client receives multiple configure events before it can + * respond to one, it is free to discard all but the last event it + * received. + * @param serial serial of the configure event + */ + void (*configure)(void *data, + struct xdg_surface *xdg_surface, + uint32_t serial); +}; + +/** + * @ingroup iface_xdg_surface + */ +static inline int +xdg_surface_add_listener(struct xdg_surface *xdg_surface, + const struct xdg_surface_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_surface, + (void (**)(void)) listener, data); +} + +#define XDG_SURFACE_DESTROY 0 +#define XDG_SURFACE_GET_TOPLEVEL 1 +#define XDG_SURFACE_GET_POPUP 2 +#define XDG_SURFACE_SET_WINDOW_GEOMETRY 3 +#define XDG_SURFACE_ACK_CONFIGURE 4 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_surface + */ +#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1 + +/** @ingroup iface_xdg_surface */ +static inline void +xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data); +} + +/** @ingroup iface_xdg_surface */ +static inline void * +xdg_surface_get_user_data(struct xdg_surface *xdg_surface) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface); +} + +static inline uint32_t +xdg_surface_get_version(struct xdg_surface *xdg_surface) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_surface); +} + +/** + * @ingroup iface_xdg_surface + * + * Destroy the xdg_surface object. An xdg_surface must only be destroyed + * after its role object has been destroyed. + */ +static inline void +xdg_surface_destroy(struct xdg_surface *xdg_surface) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_surface); +} + +/** + * @ingroup iface_xdg_surface + * + * This creates an xdg_toplevel object for the given xdg_surface and gives + * the associated wl_surface the xdg_toplevel role. + * + * See the documentation of xdg_toplevel for more details about what an + * xdg_toplevel is and how it is used. + */ +static inline struct xdg_toplevel * +xdg_surface_get_toplevel(struct xdg_surface *xdg_surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_surface, + XDG_SURFACE_GET_TOPLEVEL, &xdg_toplevel_interface, NULL); + + return (struct xdg_toplevel *) id; +} + +/** + * @ingroup iface_xdg_surface + * + * This creates an xdg_popup object for the given xdg_surface and gives + * the associated wl_surface the xdg_popup role. + * + * If null is passed as a parent, a parent surface must be specified using + * some other protocol, before committing the initial state. + * + * See the documentation of xdg_popup for more details about what an + * xdg_popup is and how it is used. + */ +static inline struct xdg_popup * +xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_surface, + XDG_SURFACE_GET_POPUP, &xdg_popup_interface, NULL, parent, positioner); + + return (struct xdg_popup *) id; +} + +/** + * @ingroup iface_xdg_surface + * + * The window geometry of a surface is its "visible bounds" from the + * user's perspective. Client-side decorations often have invisible + * portions like drop-shadows which should be ignored for the + * purposes of aligning, placing and constraining windows. + * + * The window geometry is double buffered, and will be applied at the + * time wl_surface.commit of the corresponding wl_surface is called. + * + * When maintaining a position, the compositor should treat the (x, y) + * coordinate of the window geometry as the top left corner of the window. + * A client changing the (x, y) window geometry coordinate should in + * general not alter the position of the window. + * + * Once the window geometry of the surface is set, it is not possible to + * unset it, and it will remain the same until set_window_geometry is + * called again, even if a new subsurface or buffer is attached. + * + * If never set, the value is the full bounds of the surface, + * including any subsurfaces. This updates dynamically on every + * commit. This unset is meant for extremely simple clients. + * + * The arguments are given in the surface-local coordinate space of + * the wl_surface associated with this xdg_surface. + * + * The width and height must be greater than zero. Setting an invalid size + * will raise an error. When applied, the effective window geometry will be + * the set window geometry clamped to the bounding rectangle of the + * combined geometry of the surface of the xdg_surface and the associated + * subsurfaces. + */ +static inline void +xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_SET_WINDOW_GEOMETRY, x, y, width, height); +} + +/** + * @ingroup iface_xdg_surface + * + * When a configure event is received, if a client commits the + * surface in response to the configure event, then the client + * must make an ack_configure request sometime before the commit + * request, passing along the serial of the configure event. + * + * For instance, for toplevel surfaces the compositor might use this + * information to move a surface to the top left only when the client has + * drawn itself for the maximized or fullscreen state. + * + * If the client receives multiple configure events before it + * can respond to one, it only has to ack the last configure event. + * + * A client is not required to commit immediately after sending + * an ack_configure request - it may even ack_configure several times + * before its next surface commit. + * + * A client may send multiple ack_configure requests before committing, but + * only the last request sent before a commit indicates which configure + * event the client really is responding to. + */ +static inline void +xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_surface, + XDG_SURFACE_ACK_CONFIGURE, serial); +} + +#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM +#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM +/** + * @ingroup iface_xdg_toplevel + * edge values for resizing + * + * These values are used to indicate which edge of a surface + * is being dragged in a resize operation. + */ +enum xdg_toplevel_resize_edge { + XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0, + XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2, + XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6, + XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8, + XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9, + XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10, +}; +#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */ + +#ifndef XDG_TOPLEVEL_STATE_ENUM +#define XDG_TOPLEVEL_STATE_ENUM +/** + * @ingroup iface_xdg_toplevel + * the surface is tiled + * + * The window is currently in a tiled layout and the bottom edge is + * considered to be adjacent to another part of the tiling grid. + */ +enum xdg_toplevel_state { + /** + * the surface is maximized + */ + XDG_TOPLEVEL_STATE_MAXIMIZED = 1, + /** + * the surface is fullscreen + */ + XDG_TOPLEVEL_STATE_FULLSCREEN = 2, + /** + * the surface is being resized + */ + XDG_TOPLEVEL_STATE_RESIZING = 3, + /** + * the surface is now activated + */ + XDG_TOPLEVEL_STATE_ACTIVATED = 4, + /** + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_LEFT = 5, + /** + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_RIGHT = 6, + /** + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_TOP = 7, + /** + * @since 2 + */ + XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8, +}; +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2 +#endif /* XDG_TOPLEVEL_STATE_ENUM */ + +/** + * @ingroup iface_xdg_toplevel + * @struct xdg_toplevel_listener + */ +struct xdg_toplevel_listener { + /** + * suggest a surface change + * + * This configure event asks the client to resize its toplevel + * surface or to change its state. The configured state should not + * be applied immediately. See xdg_surface.configure for details. + * + * The width and height arguments specify a hint to the window + * about how its surface should be resized in window geometry + * coordinates. See set_window_geometry. + * + * If the width or height arguments are zero, it means the client + * should decide its own window dimension. This may happen when the + * compositor needs to configure the state of the surface but + * doesn't have any information about any previous or expected + * dimension. + * + * The states listed in the event specify how the width/height + * arguments should be interpreted, and possibly how it should be + * drawn. + * + * Clients must send an ack_configure in response to this event. + * See xdg_surface.configure and xdg_surface.ack_configure for + * details. + */ + void (*configure)(void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width, + int32_t height, + struct wl_array *states); + /** + * surface wants to be closed + * + * The close event is sent by the compositor when the user wants + * the surface to be closed. This should be equivalent to the user + * clicking the close button in client-side decorations, if your + * application has any. + * + * This is only a request that the user intends to close the + * window. The client may choose to ignore this request, or show a + * dialog to ask the user to save their data, etc. + */ + void (*close)(void *data, + struct xdg_toplevel *xdg_toplevel); +}; + +/** + * @ingroup iface_xdg_toplevel + */ +static inline int +xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel, + const struct xdg_toplevel_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_toplevel, + (void (**)(void)) listener, data); +} + +#define XDG_TOPLEVEL_DESTROY 0 +#define XDG_TOPLEVEL_SET_PARENT 1 +#define XDG_TOPLEVEL_SET_TITLE 2 +#define XDG_TOPLEVEL_SET_APP_ID 3 +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU 4 +#define XDG_TOPLEVEL_MOVE 5 +#define XDG_TOPLEVEL_RESIZE 6 +#define XDG_TOPLEVEL_SET_MAX_SIZE 7 +#define XDG_TOPLEVEL_SET_MIN_SIZE 8 +#define XDG_TOPLEVEL_SET_MAXIMIZED 9 +#define XDG_TOPLEVEL_UNSET_MAXIMIZED 10 +#define XDG_TOPLEVEL_SET_FULLSCREEN 11 +#define XDG_TOPLEVEL_UNSET_FULLSCREEN 12 +#define XDG_TOPLEVEL_SET_MINIMIZED 13 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1 + +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_toplevel + */ +#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1 + +/** @ingroup iface_xdg_toplevel */ +static inline void +xdg_toplevel_set_user_data(struct xdg_toplevel *xdg_toplevel, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel, user_data); +} + +/** @ingroup iface_xdg_toplevel */ +static inline void * +xdg_toplevel_get_user_data(struct xdg_toplevel *xdg_toplevel) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel); +} + +static inline uint32_t +xdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel); +} + +/** + * @ingroup iface_xdg_toplevel + * + * This request destroys the role surface and unmaps the surface; + * see "Unmapping" behavior in interface section for details. + */ +static inline void +xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_toplevel); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set the "parent" of this surface. This surface should be stacked + * above the parent surface and all other ancestor surfaces. + * + * Parent windows should be set on dialogs, toolboxes, or other + * "auxiliary" surfaces, so that the parent is raised when the dialog + * is raised. + * + * Setting a null parent for a child window removes any parent-child + * relationship for the child. Setting a null parent for a window which + * currently has no parent is a no-op. + * + * If the parent is unmapped then its children are managed as + * though the parent of the now-unmapped parent has become the + * parent of this surface. If no parent exists for the now-unmapped + * parent then the children are managed as though they have no + * parent surface. + */ +static inline void +xdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel *parent) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_PARENT, parent); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a short title for the surface. + * + * This string may be used to identify the surface in a task bar, + * window list, or other user interface elements provided by the + * compositor. + * + * The string must be encoded in UTF-8. + */ +static inline void +xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_TITLE, title); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set an application identifier for the surface. + * + * The app ID identifies the general class of applications to which + * the surface belongs. The compositor can use this to group multiple + * surfaces together, or to determine how to launch a new application. + * + * For D-Bus activatable applications, the app ID is used as the D-Bus + * service name. + * + * The compositor shell will try to group application surfaces together + * by their app ID. As a best practice, it is suggested to select app + * ID's that match the basename of the application's .desktop file. + * For example, "org.freedesktop.FooViewer" where the .desktop file is + * "org.freedesktop.FooViewer.desktop". + * + * Like other properties, a set_app_id request can be sent after the + * xdg_toplevel has been mapped to update the property. + * + * See the desktop-entry specification [0] for more details on + * application identifiers and how they relate to well-known D-Bus + * names and .desktop files. + * + * [0] http://standards.freedesktop.org/desktop-entry-spec/ + */ +static inline void +xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_APP_ID, app_id); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Clients implementing client-side decorations might want to show + * a context menu when right-clicking on the decorations, giving the + * user a menu that they can use to maximize or minimize the window. + * + * This request asks the compositor to pop up such a window menu at + * the given position, relative to the local surface coordinates of + * the parent surface. There are no guarantees as to what menu items + * the window menu contains. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. + */ +static inline void +xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SHOW_WINDOW_MENU, seat, serial, x, y); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Start an interactive, user-driven move of the surface. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. The passed + * serial is used to determine the type of interactive move (touch, + * pointer, etc). + * + * The server may ignore move requests depending on the state of + * the surface (e.g. fullscreen or maximized), or if the passed serial + * is no longer valid. + * + * If triggered, the surface will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the move. It is up to the + * compositor to visually indicate that the move is taking place, such as + * updating a pointer cursor, during the move. There is no guarantee + * that the device focus will return when the move is completed. + */ +static inline void +xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_MOVE, seat, serial); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Start a user-driven, interactive resize of the surface. + * + * This request must be used in response to some sort of user action + * like a button press, key press, or touch down event. The passed + * serial is used to determine the type of interactive resize (touch, + * pointer, etc). + * + * The server may ignore resize requests depending on the state of + * the surface (e.g. fullscreen or maximized). + * + * If triggered, the client will receive configure events with the + * "resize" state enum value and the expected sizes. See the "resize" + * enum value for more details about what is required. The client + * must also acknowledge configure events using "ack_configure". After + * the resize is completed, the client will receive another "configure" + * event without the resize state. + * + * If triggered, the surface also will lose the focus of the device + * (wl_pointer, wl_touch, etc) used for the resize. It is up to the + * compositor to visually indicate that the resize is taking place, + * such as updating a pointer cursor, during the resize. There is no + * guarantee that the device focus will return when the resize is + * completed. + * + * The edges parameter specifies how the surface should be resized, + * and is one of the values of the resize_edge enum. The compositor + * may use this information to update the surface position for + * example when dragging the top left corner. The compositor may also + * use this information to adapt its behavior, e.g. choose an + * appropriate cursor image. + */ +static inline void +xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_RESIZE, seat, serial, edges); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a maximum size for the window. + * + * The client can specify a maximum size so that the compositor does + * not try to configure the window beyond this size. + * + * The width and height arguments are in window geometry coordinates. + * See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered. They will get applied + * on the next commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the maximum + * size. The compositor may decide to ignore the values set by the + * client and request a larger size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected maximum size in the given dimension. + * As a result, a client wishing to reset the maximum size + * to an unspecified state can use zero for width and height in the + * request. + * + * Requesting a maximum size to be smaller than the minimum size of + * a surface is illegal and will result in a protocol error. + * + * The width and height must be greater than or equal to zero. Using + * strictly negative values for width and height will result in a + * protocol error. + */ +static inline void +xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MAX_SIZE, width, height); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Set a minimum size for the window. + * + * The client can specify a minimum size so that the compositor does + * not try to configure the window below this size. + * + * The width and height arguments are in window geometry coordinates. + * See xdg_surface.set_window_geometry. + * + * Values set in this way are double-buffered. They will get applied + * on the next commit. + * + * The compositor can use this information to allow or disallow + * different states like maximize or fullscreen and draw accurate + * animations. + * + * Similarly, a tiling window manager may use this information to + * place and resize client windows in a more effective way. + * + * The client should not rely on the compositor to obey the minimum + * size. The compositor may decide to ignore the values set by the + * client and request a smaller size. + * + * If never set, or a value of zero in the request, means that the + * client has no expected minimum size in the given dimension. + * As a result, a client wishing to reset the minimum size + * to an unspecified state can use zero for width and height in the + * request. + * + * Requesting a minimum size to be larger than the maximum size of + * a surface is illegal and will result in a protocol error. + * + * The width and height must be greater than or equal to zero. Using + * strictly negative values for width and height will result in a + * protocol error. + */ +static inline void +xdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MIN_SIZE, width, height); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Maximize the surface. + * + * After requesting that the surface should be maximized, the compositor + * will respond by emitting a configure event. Whether this configure + * actually sets the window maximized is subject to compositor policies. + * The client must then update its content, drawing in the configured + * state. The client must also acknowledge the configure when committing + * the new content (see ack_configure). + * + * It is up to the compositor to decide how and where to maximize the + * surface, for example which output and what region of the screen should + * be used. + * + * If the surface was already maximized, the compositor will still emit + * a configure event with the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no direct + * effect. It may alter the state the surface is returned to when + * unmaximized unless overridden by the compositor. + */ +static inline void +xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MAXIMIZED); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Unmaximize the surface. + * + * After requesting that the surface should be unmaximized, the compositor + * will respond by emitting a configure event. Whether this actually + * un-maximizes the window is subject to compositor policies. + * If available and applicable, the compositor will include the window + * geometry dimensions the window had prior to being maximized in the + * configure event. The client must then update its content, drawing it in + * the configured state. The client must also acknowledge the configure + * when committing the new content (see ack_configure). + * + * It is up to the compositor to position the surface after it was + * unmaximized; usually the position the surface had before maximizing, if + * applicable. + * + * If the surface was already not maximized, the compositor will still + * emit a configure event without the "maximized" state. + * + * If the surface is in a fullscreen state, this request has no direct + * effect. It may alter the state the surface is returned to when + * unmaximized unless overridden by the compositor. + */ +static inline void +xdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_UNSET_MAXIMIZED); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Make the surface fullscreen. + * + * After requesting that the surface should be fullscreened, the + * compositor will respond by emitting a configure event. Whether the + * client is actually put into a fullscreen state is subject to compositor + * policies. The client must also acknowledge the configure when + * committing the new content (see ack_configure). + * + * The output passed by the request indicates the client's preference as + * to which display it should be set fullscreen on. If this value is NULL, + * it's up to the compositor to choose which display will be used to map + * this surface. + * + * If the surface doesn't cover the whole output, the compositor will + * position the surface in the center of the output and compensate with + * with border fill covering the rest of the output. The content of the + * border fill is undefined, but should be assumed to be in some way that + * attempts to blend into the surrounding area (e.g. solid black). + * + * If the fullscreened surface is not opaque, the compositor must make + * sure that other screen content not part of the same surface tree (made + * up of subsurfaces, popups or similarly coupled surfaces) are not + * visible below the fullscreened surface. + */ +static inline void +xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_FULLSCREEN, output); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Make the surface no longer fullscreen. + * + * After requesting that the surface should be unfullscreened, the + * compositor will respond by emitting a configure event. + * Whether this actually removes the fullscreen state of the client is + * subject to compositor policies. + * + * Making a surface unfullscreen sets states for the surface based on the following: + * * the state(s) it may have had before becoming fullscreen + * * any state(s) decided by the compositor + * * any state(s) requested by the client while the surface was fullscreen + * + * The compositor may include the previous window geometry dimensions in + * the configure event, if applicable. + * + * The client must also acknowledge the configure when committing the new + * content (see ack_configure). + */ +static inline void +xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_UNSET_FULLSCREEN); +} + +/** + * @ingroup iface_xdg_toplevel + * + * Request that the compositor minimize your surface. There is no + * way to know if the surface is currently minimized, nor is there + * any way to unset minimization on this surface. + * + * If you are looking to throttle redrawing when minimized, please + * instead use the wl_surface.frame event for this, as this will + * also work with live previews on windows in Alt-Tab, Expose or + * similar compositor features. + */ +static inline void +xdg_toplevel_set_minimized(struct xdg_toplevel *xdg_toplevel) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_toplevel, + XDG_TOPLEVEL_SET_MINIMIZED); +} + +#ifndef XDG_POPUP_ERROR_ENUM +#define XDG_POPUP_ERROR_ENUM +enum xdg_popup_error { + /** + * tried to grab after being mapped + */ + XDG_POPUP_ERROR_INVALID_GRAB = 0, +}; +#endif /* XDG_POPUP_ERROR_ENUM */ + +/** + * @ingroup iface_xdg_popup + * @struct xdg_popup_listener + */ +struct xdg_popup_listener { + /** + * configure the popup surface + * + * This event asks the popup surface to configure itself given + * the configuration. The configured state should not be applied + * immediately. See xdg_surface.configure for details. + * + * The x and y arguments represent the position the popup was + * placed at given the xdg_positioner rule, relative to the upper + * left corner of the window geometry of the parent surface. + * + * For version 2 or older, the configure event for an xdg_popup is + * only ever sent once for the initial configuration. Starting with + * version 3, it may be sent again if the popup is setup with an + * xdg_positioner with set_reactive requested, or in response to + * xdg_popup.reposition requests. + * @param x x position relative to parent surface window geometry + * @param y y position relative to parent surface window geometry + * @param width window geometry width + * @param height window geometry height + */ + void (*configure)(void *data, + struct xdg_popup *xdg_popup, + int32_t x, + int32_t y, + int32_t width, + int32_t height); + /** + * popup interaction is done + * + * The popup_done event is sent out when a popup is dismissed by + * the compositor. The client should destroy the xdg_popup object + * at this point. + */ + void (*popup_done)(void *data, + struct xdg_popup *xdg_popup); + /** + * signal the completion of a repositioned request + * + * The repositioned event is sent as part of a popup + * configuration sequence, together with xdg_popup.configure and + * lastly xdg_surface.configure to notify the completion of a + * reposition request. + * + * The repositioned event is to notify about the completion of a + * xdg_popup.reposition request. The token argument is the token + * passed in the xdg_popup.reposition request. + * + * Immediately after this event is emitted, xdg_popup.configure and + * xdg_surface.configure will be sent with the updated size and + * position, as well as a new configure serial. + * + * The client should optionally update the content of the popup, + * but must acknowledge the new popup configuration for the new + * position to take effect. See xdg_surface.ack_configure for + * details. + * @param token reposition request token + * @since 3 + */ + void (*repositioned)(void *data, + struct xdg_popup *xdg_popup, + uint32_t token); +}; + +/** + * @ingroup iface_xdg_popup + */ +static inline int +xdg_popup_add_listener(struct xdg_popup *xdg_popup, + const struct xdg_popup_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) xdg_popup, + (void (**)(void)) listener, data); +} + +#define XDG_POPUP_DESTROY 0 +#define XDG_POPUP_GRAB 1 +#define XDG_POPUP_REPOSITION 2 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITIONED_SINCE_VERSION 3 + +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_GRAB_SINCE_VERSION 1 +/** + * @ingroup iface_xdg_popup + */ +#define XDG_POPUP_REPOSITION_SINCE_VERSION 3 + +/** @ingroup iface_xdg_popup */ +static inline void +xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data); +} + +/** @ingroup iface_xdg_popup */ +static inline void * +xdg_popup_get_user_data(struct xdg_popup *xdg_popup) +{ + return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup); +} + +static inline uint32_t +xdg_popup_get_version(struct xdg_popup *xdg_popup) +{ + return wl_proxy_get_version((struct wl_proxy *) xdg_popup); +} + +/** + * @ingroup iface_xdg_popup + * + * This destroys the popup. Explicitly destroying the xdg_popup + * object will also dismiss the popup, and unmap the surface. + * + * If this xdg_popup is not the "topmost" popup, a protocol error + * will be sent. + */ +static inline void +xdg_popup_destroy(struct xdg_popup *xdg_popup) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_popup, + XDG_POPUP_DESTROY); + + wl_proxy_destroy((struct wl_proxy *) xdg_popup); +} + +/** + * @ingroup iface_xdg_popup + * + * This request makes the created popup take an explicit grab. An explicit + * grab will be dismissed when the user dismisses the popup, or when the + * client destroys the xdg_popup. This can be done by the user clicking + * outside the surface, using the keyboard, or even locking the screen + * through closing the lid or a timeout. + * + * If the compositor denies the grab, the popup will be immediately + * dismissed. + * + * This request must be used in response to some sort of user action like a + * button press, key press, or touch down event. The serial number of the + * event should be passed as 'serial'. + * + * The parent of a grabbing popup must either be an xdg_toplevel surface or + * another xdg_popup with an explicit grab. If the parent is another + * xdg_popup it means that the popups are nested, with this popup now being + * the topmost popup. + * + * Nested popups must be destroyed in the reverse order they were created + * in, e.g. the only popup you are allowed to destroy at all times is the + * topmost one. + * + * When compositors choose to dismiss a popup, they may dismiss every + * nested grabbing popup as well. When a compositor dismisses popups, it + * will follow the same dismissing order as required from the client. + * + * The parent of a grabbing popup must either be another xdg_popup with an + * active explicit grab, or an xdg_popup or xdg_toplevel, if there are no + * explicit grabs already taken. + * + * If the topmost grabbing popup is destroyed, the grab will be returned to + * the parent of the popup, if that parent previously had an explicit grab. + * + * If the parent is a grabbing popup which has already been dismissed, this + * popup will be immediately dismissed. If the parent is a popup that did + * not take an explicit grab, an error will be raised. + * + * During a popup grab, the client owning the grab will receive pointer + * and touch events for all their surfaces as normal (similar to an + * "owner-events" grab in X11 parlance), while the top most grabbing popup + * will always have keyboard focus. + */ +static inline void +xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t serial) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_popup, + XDG_POPUP_GRAB, seat, serial); +} + +/** + * @ingroup iface_xdg_popup + * + * Reposition an already-mapped popup. The popup will be placed given the + * details in the passed xdg_positioner object, and a + * xdg_popup.repositioned followed by xdg_popup.configure and + * xdg_surface.configure will be emitted in response. Any parameters set + * by the previous positioner will be discarded. + * + * The passed token will be sent in the corresponding + * xdg_popup.repositioned event. The new popup position will not take + * effect until the corresponding configure event is acknowledged by the + * client. See xdg_popup.repositioned for details. The token itself is + * opaque, and has no other special meaning. + * + * If multiple reposition requests are sent, the compositor may skip all + * but the last one. + * + * If the popup is repositioned in response to a configure event for its + * parent, the client should send an xdg_positioner.set_parent_configure + * and possibly an xdg_positioner.set_parent_size request to allow the + * compositor to properly constrain the popup. + * + * If the popup is repositioned together with a parent that is being + * resized, but not in response to a configure event, the client should + * send an xdg_positioner.set_parent_size request. + */ +static inline void +xdg_popup_reposition(struct xdg_popup *xdg_popup, struct xdg_positioner *positioner, uint32_t token) +{ + wl_proxy_marshal((struct wl_proxy *) xdg_popup, + XDG_POPUP_REPOSITION, positioner, token); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wgl_context.h b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wgl_context.h index d982118..1603f15 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wgl_context.h +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wgl_context.h @@ -104,10 +104,6 @@ typedef BOOL (WINAPI * PFN_wglShareLists)(HGLRC,HGLRC); #define wglMakeCurrent _glfw.wgl.MakeCurrent #define wglShareLists _glfw.wgl.ShareLists -#define _GLFW_RECREATION_NOT_NEEDED 0 -#define _GLFW_RECREATION_REQUIRED 1 -#define _GLFW_RECREATION_IMPOSSIBLE 2 - #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl #define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_init.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_init.c index b2aa0a3..a7a6be6 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_init.c +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_init.c @@ -143,6 +143,8 @@ static GLFWbool loadLibraries(void) GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush"); _glfw.win32.dwmapi.EnableBlurBehindWindow = (PFN_DwmEnableBlurBehindWindow) GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow"); + _glfw.win32.dwmapi.GetColorizationColor = (PFN_DwmGetColorizationColor) + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmGetColorizationColor"); } _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll"); diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_joystick.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_joystick.c index 4ffc9fb..62ad7a5 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_joystick.c +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_joystick.c @@ -356,7 +356,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user) for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) { - _GLFWjoystick* js = _glfw.joysticks + jid; + js = _glfw.joysticks + jid; if (js->present) { if (memcmp(&js->win32.guid, &di->guidInstance, sizeof(GUID)) == 0) @@ -672,11 +672,11 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) }; // Screams of horror are appropriate at this point - int state = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES); - if (state < 0 || state > 8) - state = 8; + int stateIndex = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES); + if (stateIndex < 0 || stateIndex > 8) + stateIndex = 8; - _glfwInputJoystickHat(js, pi, states[state]); + _glfwInputJoystickHat(js, pi, states[stateIndex]); pi++; break; } diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_monitor.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_monitor.c index 4f5af36..c8bae35 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_monitor.c +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_monitor.c @@ -185,6 +185,8 @@ void _glfwPollMonitorsWin32(void) display.DeviceName) == 0) { disconnected[i] = NULL; + // handle may have changed, update + EnumDisplayMonitors(NULL, NULL, monitorCallback, (LPARAM) _glfw.monitors[i]); break; } } diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_platform.h b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_platform.h index be1dc54..003b8a1 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_platform.h +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_platform.h @@ -77,6 +77,9 @@ #ifndef WM_DWMCOMPOSITIONCHANGED #define WM_DWMCOMPOSITIONCHANGED 0x031E #endif +#ifndef WM_DWMCOLORIZATIONCOLORCHANGED + #define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320 +#endif #ifndef WM_COPYGLOBALDATA #define WM_COPYGLOBALDATA 0x0049 #endif @@ -99,7 +102,7 @@ #define DISPLAY_DEVICE_ACTIVE 0x00000001 #endif #ifndef _WIN32_WINNT_WINBLUE - #define _WIN32_WINNT_WINBLUE 0x0602 + #define _WIN32_WINNT_WINBLUE 0x0603 #endif #ifndef _WIN32_WINNT_WIN8 #define _WIN32_WINNT_WIN8 0x0602 @@ -247,9 +250,11 @@ typedef BOOL (WINAPI * PFN_AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UIN typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*); typedef HRESULT (WINAPI * PFN_DwmFlush)(VOID); typedef HRESULT(WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND,const DWM_BLURBEHIND*); +typedef HRESULT (WINAPI * PFN_DwmGetColorizationColor)(DWORD*,BOOL*); #define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled #define DwmFlush _glfw.win32.dwmapi.Flush #define DwmEnableBlurBehindWindow _glfw.win32.dwmapi.EnableBlurBehindWindow +#define DwmGetColorizationColor _glfw.win32.dwmapi.GetColorizationColor // shcore.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); @@ -316,8 +321,13 @@ typedef struct _GLFWwindowWin32 GLFWbool transparent; GLFWbool scaleToMonitor; + // Cached size used to filter out duplicate events + int width, height; + // The last received cursor position, regardless of source int lastCursorPosX, lastCursorPosY; + // The last recevied high surrogate when decoding pairs of UTF-16 messages + WCHAR highSurrogate; } _GLFWwindowWin32; @@ -373,6 +383,7 @@ typedef struct _GLFWlibraryWin32 PFN_DwmIsCompositionEnabled IsCompositionEnabled; PFN_DwmFlush Flush; PFN_DwmEnableBlurBehindWindow EnableBlurBehindWindow; + PFN_DwmGetColorizationColor GetColorizationColor; } dwmapi; struct { diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_window.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_window.c index 0ce22ee..d17b6da 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_window.c +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/win32_window.c @@ -377,12 +377,17 @@ static void updateWindowStyles(const _GLFWwindow* window) // static void updateFramebufferTransparency(const _GLFWwindow* window) { - BOOL enabled; + BOOL composition, opaque; + DWORD color; if (!IsWindowsVistaOrGreater()) return; - if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled) + if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition) + return; + + if (IsWindows8OrGreater() || + (SUCCEEDED(DwmGetColorizationColor(&color, &opaque)) && !opaque)) { HRGN region = CreateRectRgn(0, 0, -1, -1); DWM_BLURBEHIND bb = {0}; @@ -390,37 +395,18 @@ static void updateFramebufferTransparency(const _GLFWwindow* window) bb.hRgnBlur = region; bb.fEnable = TRUE; - if (SUCCEEDED(DwmEnableBlurBehindWindow(window->win32.handle, &bb))) - { - // Decorated windows don't repaint the transparent background - // leaving a trail behind animations - // HACK: Making the window layered with a transparency color key - // seems to fix this. Normally, when specifying - // a transparency color key to be used when composing the - // layered window, all pixels painted by the window in this - // color will be transparent. That doesn't seem to be the - // case anymore, at least when used with blur behind window - // plus negative region. - LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); - exStyle |= WS_EX_LAYERED; - SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle); - - // Using a color key not equal to black to fix the trailing - // issue. When set to black, something is making the hit test - // not resize with the window frame. - SetLayeredWindowAttributes(window->win32.handle, - RGB(255, 0, 255), 255, LWA_COLORKEY); - } - + DwmEnableBlurBehindWindow(window->win32.handle, &bb); DeleteObject(region); } else { - LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); - exStyle &= ~WS_EX_LAYERED; - SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle); - RedrawWindow(window->win32.handle, NULL, NULL, - RDW_ERASE | RDW_INVALIDATE | RDW_FRAME); + // HACK: Disable framebuffer transparency on Windows 7 when the + // colorization color is opaque, because otherwise the window + // contents is blended additively with the previous frame instead + // of replacing it + DWM_BLURBEHIND bb = {0}; + bb.dwFlags = DWM_BB_ENABLE; + DwmEnableBlurBehindWindow(window->win32.handle, &bb); } } @@ -519,7 +505,17 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_NCCREATE: { if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32()) - EnableNonClientDpiScaling(hWnd); + { + const CREATESTRUCTW* cs = (const CREATESTRUCTW*) lParam; + const _GLFWwndconfig* wndconfig = cs->lpCreateParams; + + // On per-monitor DPI aware V1 systems, only enable + // non-client scaling for windows that scale the client area + // We need WM_GETDPISCALEDSIZE from V2 to keep the client + // area static when the non-client area is scaled + if (wndconfig && wndconfig->scaleToMonitor) + EnableNonClientDpiScaling(hWnd); + } break; } @@ -645,11 +641,35 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_CHAR: case WM_SYSCHAR: - case WM_UNICHAR: { - const GLFWbool plain = (uMsg != WM_SYSCHAR); + if (wParam >= 0xd800 && wParam <= 0xdbff) + window->win32.highSurrogate = (WCHAR) wParam; + else + { + unsigned int codepoint = 0; + + if (wParam >= 0xdc00 && wParam <= 0xdfff) + { + if (window->win32.highSurrogate) + { + codepoint += (window->win32.highSurrogate - 0xd800) << 10; + codepoint += (WCHAR) wParam - 0xdc00; + codepoint += 0x10000; + } + } + else + codepoint = (WCHAR) wParam; + + window->win32.highSurrogate = 0; + _glfwInputChar(window, codepoint, getKeyMods(), uMsg != WM_SYSCHAR); + } - if (uMsg == WM_UNICHAR && wParam == UNICODE_NOCHAR) + return 0; + } + + case WM_UNICHAR: + { + if (wParam == UNICODE_NOCHAR) { // WM_UNICHAR is not sent by Windows, but is sent by some // third-party input method engine @@ -657,7 +677,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, return TRUE; } - _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), plain); + _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GLFW_TRUE); return 0; } @@ -944,6 +964,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_SIZE: { + const int width = LOWORD(lParam); + const int height = HIWORD(lParam); const GLFWbool iconified = wParam == SIZE_MINIMIZED; const GLFWbool maximized = wParam == SIZE_MAXIMIZED || (window->win32.maximized && @@ -958,8 +980,14 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, if (window->win32.maximized != maximized) _glfwInputWindowMaximize(window, maximized); - _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam)); - _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam)); + if (width != window->win32.width || height != window->win32.height) + { + window->win32.width = width; + window->win32.height = height; + + _glfwInputFramebufferSize(window, width, height); + _glfwInputWindowSize(window, width, height); + } if (window->monitor && window->win32.iconified != iconified) { @@ -1073,6 +1101,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, } case WM_DWMCOMPOSITIONCHANGED: + case WM_DWMCOLORIZATIONCOLORCHANGED: { if (window->win32.transparent) updateFramebufferTransparency(window); @@ -1112,9 +1141,11 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, const float xscale = HIWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI; const float yscale = LOWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI; - // Only apply the suggested size if the OS is new enough to have - // sent a WM_GETDPISCALEDSIZE before this - if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32()) + // Resize windowed mode windows that either permit rescaling or that + // need it to compensate for non-client area scaling + if (!window->monitor && + (window->win32.scaleToMonitor || + _glfwIsWindows10CreatorsUpdateOrGreaterWin32())) { RECT* suggested = (RECT*) lParam; SetWindowPos(window->win32.handle, HWND_TOP, @@ -1229,7 +1260,7 @@ static int createNativeWindow(_GLFWwindow* window, NULL, // No parent window NULL, // No window menu GetModuleHandleW(NULL), - NULL); + (LPVOID) wndconfig); free(wideTitle); @@ -1296,6 +1327,8 @@ static int createNativeWindow(_GLFWwindow* window, window->win32.transparent = GLFW_TRUE; } + _glfwPlatformGetWindowSize(window, &window->win32.width, &window->win32.height); + return GLFW_TRUE; } @@ -1797,7 +1830,8 @@ int _glfwPlatformWindowHovered(_GLFWwindow* window) int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { - BOOL enabled; + BOOL composition, opaque; + DWORD color; if (!window->win32.transparent) return GLFW_FALSE; @@ -1805,7 +1839,20 @@ int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) if (!IsWindowsVistaOrGreater()) return GLFW_FALSE; - return SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled; + if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition) + return GLFW_FALSE; + + if (!IsWindows8OrGreater()) + { + // HACK: Disable framebuffer transparency on Windows 7 when the + // colorization color is opaque, because otherwise the window + // contents is blended additively with the previous frame instead + // of replacing it + if (FAILED(DwmGetColorizationColor(&color, &opaque)) || opaque) + return GLFW_FALSE; + } + + return GLFW_TRUE; } void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/window.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/window.c index 4b356b2..44de03b 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/window.c +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/window.c @@ -1099,3 +1099,4 @@ GLFWAPI void glfwPostEmptyEvent(void) _GLFW_REQUIRE_INIT(); _glfwPlatformPostEmptyEvent(); } + diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wl_init.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wl_init.c index 97b5367..49e7cc5 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wl_init.c +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wl_init.c @@ -347,9 +347,9 @@ static void pointerHandleAxis(void* data, axis == WL_POINTER_AXIS_VERTICAL_SCROLL); if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) - x = wl_fixed_to_double(value) * scrollFactor; + x = -wl_fixed_to_double(value) * scrollFactor; else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) - y = wl_fixed_to_double(value) * scrollFactor; + y = -wl_fixed_to_double(value) * scrollFactor; _glfwInputScroll(window, x, y); } diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wl_monitor.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wl_monitor.c index 48b25b9..a7b05c6 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wl_monitor.c +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wl_monitor.c @@ -88,6 +88,14 @@ static void outputHandleDone(void* data, struct wl_output* output) { struct _GLFWmonitor *monitor = data; + if (monitor->widthMM <= 0 || monitor->heightMM <= 0) + { + // If Wayland does not provide a physical size, assume the default 96 DPI + const GLFWvidmode* mode = &monitor->modes[monitor->wl.currentMode]; + monitor->widthMM = (int) (mode->width * 25.4f / 96.f); + monitor->heightMM = (int) (mode->height * 25.4f / 96.f); + } + _glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST); } diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wl_window.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wl_window.c index a902571..d10861c 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wl_window.c +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/wl_window.c @@ -208,8 +208,8 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image) if (fd < 0) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: Creating a buffer file for %d B failed: %m", - length); + "Wayland: Creating a buffer file for %d B failed: %s", + length, strerror(errno)); return NULL; } @@ -217,7 +217,7 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image) if (data == MAP_FAILED) { _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: mmap failed: %m"); + "Wayland: mmap failed: %s", strerror(errno)); close(fd); return NULL; } @@ -312,10 +312,10 @@ static void createDecorations(_GLFWwindow* window) static void destroyDecoration(_GLFWdecorationWayland* decoration) { - if (decoration->surface) - wl_surface_destroy(decoration->surface); if (decoration->subsurface) wl_subsurface_destroy(decoration->subsurface); + if (decoration->surface) + wl_surface_destroy(decoration->surface); if (decoration->viewport) wp_viewport_destroy(decoration->viewport); decoration->surface = NULL; @@ -870,10 +870,17 @@ static void handleEvents(int timeout) if (read_ret != 8) return; - for (i = 0; i < repeats; ++i) - _glfwInputKey(_glfw.wl.keyboardFocus, _glfw.wl.keyboardLastKey, - _glfw.wl.keyboardLastScancode, GLFW_REPEAT, - _glfw.wl.xkb.modifiers); + if (_glfw.wl.keyboardFocus) + { + for (i = 0; i < repeats; ++i) + { + _glfwInputKey(_glfw.wl.keyboardFocus, + _glfw.wl.keyboardLastKey, + _glfw.wl.keyboardLastScancode, + GLFW_REPEAT, + _glfw.wl.xkb.modifiers); + } + } } if (fds[2].revents & POLLIN) @@ -1111,8 +1118,10 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) { _glfwPlatformGetWindowSize(window, width, height); - *width *= window->wl.scale; - *height *= window->wl.scale; + if (width) + *width *= window->wl.scale; + if (height) + *height *= window->wl.scale; } void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_init.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_init.c index 2f220ec..87b3eb7 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_init.c +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_init.c @@ -38,24 +38,15 @@ #include -// Translate an X11 key code to a GLFW key code. +// Translate the X11 KeySyms for a key to a GLFW key code +// NOTE: This is only used as a fallback, in case the XKB method fails +// It is layout-dependent and will fail partially on most non-US layouts // -static int translateKeyCode(int scancode) +static int translateKeySyms(const KeySym* keysyms, int width) { - int keySym; - - // Valid key code range is [8,255], according to the Xlib manual - if (scancode < 8 || scancode > 255) - return GLFW_KEY_UNKNOWN; - - if (_glfw.x11.xkb.available) + if (width > 1) { - // Try secondary keysym, for numeric keypad keys - // Note: This way we always force "NumLock = ON", which is intentional - // since the returned key code should correspond to a physical - // location. - keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 1); - switch (keySym) + switch (keysyms[1]) { case XK_KP_0: return GLFW_KEY_KP_0; case XK_KP_1: return GLFW_KEY_KP_1; @@ -73,22 +64,9 @@ static int translateKeyCode(int scancode) case XK_KP_Enter: return GLFW_KEY_KP_ENTER; default: break; } - - // Now try primary keysym for function keys (non-printable keys) - // These should not depend on the current keyboard layout - keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, _glfw.x11.xkb.group, 0); - } - else - { - int dummy; - KeySym* keySyms; - - keySyms = XGetKeyboardMapping(_glfw.x11.display, scancode, 1, &dummy); - keySym = keySyms[0]; - XFree(keySyms); } - switch (keySym) + switch (keysyms[0]) { case XK_Escape: return GLFW_KEY_ESCAPE; case XK_Tab: return GLFW_KEY_TAB; @@ -232,7 +210,7 @@ static int translateKeyCode(int scancode) // static void createKeyTables(void) { - int scancode, key; + int scancode, scancodeMin, scancodeMax; memset(_glfw.x11.keycodes, -1, sizeof(_glfw.x11.keycodes)); memset(_glfw.x11.scancodes, -1, sizeof(_glfw.x11.scancodes)); @@ -242,89 +220,217 @@ static void createKeyTables(void) // Use XKB to determine physical key locations independently of the // current keyboard layout - char name[XkbKeyNameLength + 1]; XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd); - XkbGetNames(_glfw.x11.display, XkbKeyNamesMask, desc); + XkbGetNames(_glfw.x11.display, XkbKeyNamesMask | XkbKeyAliasesMask, desc); + + scancodeMin = desc->min_key_code; + scancodeMax = desc->max_key_code; + + const struct + { + int key; + char* name; + } keymap[] = + { + { GLFW_KEY_GRAVE_ACCENT, "TLDE" }, + { GLFW_KEY_1, "AE01" }, + { GLFW_KEY_2, "AE02" }, + { GLFW_KEY_3, "AE03" }, + { GLFW_KEY_4, "AE04" }, + { GLFW_KEY_5, "AE05" }, + { GLFW_KEY_6, "AE06" }, + { GLFW_KEY_7, "AE07" }, + { GLFW_KEY_8, "AE08" }, + { GLFW_KEY_9, "AE09" }, + { GLFW_KEY_0, "AE10" }, + { GLFW_KEY_MINUS, "AE11" }, + { GLFW_KEY_EQUAL, "AE12" }, + { GLFW_KEY_Q, "AD01" }, + { GLFW_KEY_W, "AD02" }, + { GLFW_KEY_E, "AD03" }, + { GLFW_KEY_R, "AD04" }, + { GLFW_KEY_T, "AD05" }, + { GLFW_KEY_Y, "AD06" }, + { GLFW_KEY_U, "AD07" }, + { GLFW_KEY_I, "AD08" }, + { GLFW_KEY_O, "AD09" }, + { GLFW_KEY_P, "AD10" }, + { GLFW_KEY_LEFT_BRACKET, "AD11" }, + { GLFW_KEY_RIGHT_BRACKET, "AD12" }, + { GLFW_KEY_A, "AC01" }, + { GLFW_KEY_S, "AC02" }, + { GLFW_KEY_D, "AC03" }, + { GLFW_KEY_F, "AC04" }, + { GLFW_KEY_G, "AC05" }, + { GLFW_KEY_H, "AC06" }, + { GLFW_KEY_J, "AC07" }, + { GLFW_KEY_K, "AC08" }, + { GLFW_KEY_L, "AC09" }, + { GLFW_KEY_SEMICOLON, "AC10" }, + { GLFW_KEY_APOSTROPHE, "AC11" }, + { GLFW_KEY_Z, "AB01" }, + { GLFW_KEY_X, "AB02" }, + { GLFW_KEY_C, "AB03" }, + { GLFW_KEY_V, "AB04" }, + { GLFW_KEY_B, "AB05" }, + { GLFW_KEY_N, "AB06" }, + { GLFW_KEY_M, "AB07" }, + { GLFW_KEY_COMMA, "AB08" }, + { GLFW_KEY_PERIOD, "AB09" }, + { GLFW_KEY_SLASH, "AB10" }, + { GLFW_KEY_BACKSLASH, "BKSL" }, + { GLFW_KEY_WORLD_1, "LSGT" }, + { GLFW_KEY_SPACE, "SPCE" }, + { GLFW_KEY_ESCAPE, "ESC" }, + { GLFW_KEY_ENTER, "RTRN" }, + { GLFW_KEY_TAB, "TAB" }, + { GLFW_KEY_BACKSPACE, "BKSP" }, + { GLFW_KEY_INSERT, "INS" }, + { GLFW_KEY_DELETE, "DELE" }, + { GLFW_KEY_RIGHT, "RGHT" }, + { GLFW_KEY_LEFT, "LEFT" }, + { GLFW_KEY_DOWN, "DOWN" }, + { GLFW_KEY_UP, "UP" }, + { GLFW_KEY_PAGE_UP, "PGUP" }, + { GLFW_KEY_PAGE_DOWN, "PGDN" }, + { GLFW_KEY_HOME, "HOME" }, + { GLFW_KEY_END, "END" }, + { GLFW_KEY_CAPS_LOCK, "CAPS" }, + { GLFW_KEY_SCROLL_LOCK, "SCLK" }, + { GLFW_KEY_NUM_LOCK, "NMLK" }, + { GLFW_KEY_PRINT_SCREEN, "PRSC" }, + { GLFW_KEY_PAUSE, "PAUS" }, + { GLFW_KEY_F1, "FK01" }, + { GLFW_KEY_F2, "FK02" }, + { GLFW_KEY_F3, "FK03" }, + { GLFW_KEY_F4, "FK04" }, + { GLFW_KEY_F5, "FK05" }, + { GLFW_KEY_F6, "FK06" }, + { GLFW_KEY_F7, "FK07" }, + { GLFW_KEY_F8, "FK08" }, + { GLFW_KEY_F9, "FK09" }, + { GLFW_KEY_F10, "FK10" }, + { GLFW_KEY_F11, "FK11" }, + { GLFW_KEY_F12, "FK12" }, + { GLFW_KEY_F13, "FK13" }, + { GLFW_KEY_F14, "FK14" }, + { GLFW_KEY_F15, "FK15" }, + { GLFW_KEY_F16, "FK16" }, + { GLFW_KEY_F17, "FK17" }, + { GLFW_KEY_F18, "FK18" }, + { GLFW_KEY_F19, "FK19" }, + { GLFW_KEY_F20, "FK20" }, + { GLFW_KEY_F21, "FK21" }, + { GLFW_KEY_F22, "FK22" }, + { GLFW_KEY_F23, "FK23" }, + { GLFW_KEY_F24, "FK24" }, + { GLFW_KEY_F25, "FK25" }, + { GLFW_KEY_KP_0, "KP0" }, + { GLFW_KEY_KP_1, "KP1" }, + { GLFW_KEY_KP_2, "KP2" }, + { GLFW_KEY_KP_3, "KP3" }, + { GLFW_KEY_KP_4, "KP4" }, + { GLFW_KEY_KP_5, "KP5" }, + { GLFW_KEY_KP_6, "KP6" }, + { GLFW_KEY_KP_7, "KP7" }, + { GLFW_KEY_KP_8, "KP8" }, + { GLFW_KEY_KP_9, "KP9" }, + { GLFW_KEY_KP_DECIMAL, "KPDL" }, + { GLFW_KEY_KP_DIVIDE, "KPDV" }, + { GLFW_KEY_KP_MULTIPLY, "KPMU" }, + { GLFW_KEY_KP_SUBTRACT, "KPSU" }, + { GLFW_KEY_KP_ADD, "KPAD" }, + { GLFW_KEY_KP_ENTER, "KPEN" }, + { GLFW_KEY_KP_EQUAL, "KPEQ" }, + { GLFW_KEY_LEFT_SHIFT, "LFSH" }, + { GLFW_KEY_LEFT_CONTROL, "LCTL" }, + { GLFW_KEY_LEFT_ALT, "LALT" }, + { GLFW_KEY_LEFT_SUPER, "LWIN" }, + { GLFW_KEY_RIGHT_SHIFT, "RTSH" }, + { GLFW_KEY_RIGHT_CONTROL, "RCTL" }, + { GLFW_KEY_RIGHT_ALT, "RALT" }, + { GLFW_KEY_RIGHT_ALT, "LVL3" }, + { GLFW_KEY_RIGHT_ALT, "MDSW" }, + { GLFW_KEY_RIGHT_SUPER, "RWIN" }, + { GLFW_KEY_MENU, "MENU" } + }; // Find the X11 key code -> GLFW key code mapping - for (scancode = desc->min_key_code; scancode <= desc->max_key_code; scancode++) + for (scancode = scancodeMin; scancode <= scancodeMax; scancode++) { - memcpy(name, desc->names->keys[scancode].name, XkbKeyNameLength); - name[XkbKeyNameLength] = '\0'; - - // Map the key name to a GLFW key code. Note: We only map printable - // keys here, and we use the US keyboard layout. The rest of the - // keys (function keys) are mapped using traditional KeySym - // translations. - if (strcmp(name, "TLDE") == 0) key = GLFW_KEY_GRAVE_ACCENT; - else if (strcmp(name, "AE01") == 0) key = GLFW_KEY_1; - else if (strcmp(name, "AE02") == 0) key = GLFW_KEY_2; - else if (strcmp(name, "AE03") == 0) key = GLFW_KEY_3; - else if (strcmp(name, "AE04") == 0) key = GLFW_KEY_4; - else if (strcmp(name, "AE05") == 0) key = GLFW_KEY_5; - else if (strcmp(name, "AE06") == 0) key = GLFW_KEY_6; - else if (strcmp(name, "AE07") == 0) key = GLFW_KEY_7; - else if (strcmp(name, "AE08") == 0) key = GLFW_KEY_8; - else if (strcmp(name, "AE09") == 0) key = GLFW_KEY_9; - else if (strcmp(name, "AE10") == 0) key = GLFW_KEY_0; - else if (strcmp(name, "AE11") == 0) key = GLFW_KEY_MINUS; - else if (strcmp(name, "AE12") == 0) key = GLFW_KEY_EQUAL; - else if (strcmp(name, "AD01") == 0) key = GLFW_KEY_Q; - else if (strcmp(name, "AD02") == 0) key = GLFW_KEY_W; - else if (strcmp(name, "AD03") == 0) key = GLFW_KEY_E; - else if (strcmp(name, "AD04") == 0) key = GLFW_KEY_R; - else if (strcmp(name, "AD05") == 0) key = GLFW_KEY_T; - else if (strcmp(name, "AD06") == 0) key = GLFW_KEY_Y; - else if (strcmp(name, "AD07") == 0) key = GLFW_KEY_U; - else if (strcmp(name, "AD08") == 0) key = GLFW_KEY_I; - else if (strcmp(name, "AD09") == 0) key = GLFW_KEY_O; - else if (strcmp(name, "AD10") == 0) key = GLFW_KEY_P; - else if (strcmp(name, "AD11") == 0) key = GLFW_KEY_LEFT_BRACKET; - else if (strcmp(name, "AD12") == 0) key = GLFW_KEY_RIGHT_BRACKET; - else if (strcmp(name, "AC01") == 0) key = GLFW_KEY_A; - else if (strcmp(name, "AC02") == 0) key = GLFW_KEY_S; - else if (strcmp(name, "AC03") == 0) key = GLFW_KEY_D; - else if (strcmp(name, "AC04") == 0) key = GLFW_KEY_F; - else if (strcmp(name, "AC05") == 0) key = GLFW_KEY_G; - else if (strcmp(name, "AC06") == 0) key = GLFW_KEY_H; - else if (strcmp(name, "AC07") == 0) key = GLFW_KEY_J; - else if (strcmp(name, "AC08") == 0) key = GLFW_KEY_K; - else if (strcmp(name, "AC09") == 0) key = GLFW_KEY_L; - else if (strcmp(name, "AC10") == 0) key = GLFW_KEY_SEMICOLON; - else if (strcmp(name, "AC11") == 0) key = GLFW_KEY_APOSTROPHE; - else if (strcmp(name, "AB01") == 0) key = GLFW_KEY_Z; - else if (strcmp(name, "AB02") == 0) key = GLFW_KEY_X; - else if (strcmp(name, "AB03") == 0) key = GLFW_KEY_C; - else if (strcmp(name, "AB04") == 0) key = GLFW_KEY_V; - else if (strcmp(name, "AB05") == 0) key = GLFW_KEY_B; - else if (strcmp(name, "AB06") == 0) key = GLFW_KEY_N; - else if (strcmp(name, "AB07") == 0) key = GLFW_KEY_M; - else if (strcmp(name, "AB08") == 0) key = GLFW_KEY_COMMA; - else if (strcmp(name, "AB09") == 0) key = GLFW_KEY_PERIOD; - else if (strcmp(name, "AB10") == 0) key = GLFW_KEY_SLASH; - else if (strcmp(name, "BKSL") == 0) key = GLFW_KEY_BACKSLASH; - else if (strcmp(name, "LSGT") == 0) key = GLFW_KEY_WORLD_1; - else key = GLFW_KEY_UNKNOWN; - - if ((scancode >= 0) && (scancode < 256)) - _glfw.x11.keycodes[scancode] = key; + int key = GLFW_KEY_UNKNOWN; + + // Map the key name to a GLFW key code. Note: We use the US + // keyboard layout. Because function keys aren't mapped correctly + // when using traditional KeySym translations, they are mapped + // here instead. + for (int i = 0; i < sizeof(keymap) / sizeof(keymap[0]); i++) + { + if (strncmp(desc->names->keys[scancode].name, + keymap[i].name, + XkbKeyNameLength) == 0) + { + key = keymap[i].key; + break; + } + } + + // Fall back to key aliases in case the key name did not match + for (int i = 0; i < desc->names->num_key_aliases; i++) + { + if (key != GLFW_KEY_UNKNOWN) + break; + + if (strncmp(desc->names->key_aliases[i].real, + desc->names->keys[scancode].name, + XkbKeyNameLength) != 0) + { + continue; + } + + for (int j = 0; j < sizeof(keymap) / sizeof(keymap[0]); j++) + { + if (strncmp(desc->names->key_aliases[i].alias, + keymap[j].name, + XkbKeyNameLength) == 0) + { + key = keymap[j].key; + break; + } + } + } + + _glfw.x11.keycodes[scancode] = key; } XkbFreeNames(desc, XkbKeyNamesMask, True); XkbFreeKeyboard(desc, 0, True); } + else + XDisplayKeycodes(_glfw.x11.display, &scancodeMin, &scancodeMax); + + int width; + KeySym* keysyms = XGetKeyboardMapping(_glfw.x11.display, + scancodeMin, + scancodeMax - scancodeMin + 1, + &width); - for (scancode = 0; scancode < 256; scancode++) + for (scancode = scancodeMin; scancode <= scancodeMax; scancode++) { // Translate the un-translated key codes using traditional X11 KeySym // lookups if (_glfw.x11.keycodes[scancode] < 0) - _glfw.x11.keycodes[scancode] = translateKeyCode(scancode); + { + const size_t base = (scancode - scancodeMin) * width; + _glfw.x11.keycodes[scancode] = translateKeySyms(&keysyms[base], width); + } // Store the reverse translation for faster key name lookup if (_glfw.x11.keycodes[scancode] > 0) _glfw.x11.scancodes[_glfw.x11.keycodes[scancode]] = scancode; } + + XFree(keysyms); } // Check whether the IM has a usable style @@ -352,13 +458,13 @@ static GLFWbool hasUsableInputMethodStyle(void) // Check whether the specified atom is supported // -static Atom getSupportedAtom(Atom* supportedAtoms, - unsigned long atomCount, - const char* atomName) +static Atom getAtomIfSupported(Atom* supportedAtoms, + unsigned long atomCount, + const char* atomName) { const Atom atom = XInternAtom(_glfw.x11.display, atomName, False); - for (unsigned int i = 0; i < atomCount; i++) + for (unsigned long i = 0; i < atomCount; i++) { if (supportedAtoms[i] == atom) return atom; @@ -426,33 +532,33 @@ static void detectEWMH(void) // See which of the atoms we support that are supported by the WM _glfw.x11.NET_WM_STATE = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE"); _glfw.x11.NET_WM_STATE_ABOVE = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); _glfw.x11.NET_WM_STATE_FULLSCREEN = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT"); _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ"); _glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_STATE_DEMANDS_ATTENTION"); _glfw.x11.NET_WM_FULLSCREEN_MONITORS = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); _glfw.x11.NET_WM_WINDOW_TYPE = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE"); _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL"); _glfw.x11.NET_WORKAREA = - getSupportedAtom(supportedAtoms, atomCount, "_NET_WORKAREA"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_WORKAREA"); _glfw.x11.NET_CURRENT_DESKTOP = - getSupportedAtom(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_CURRENT_DESKTOP"); _glfw.x11.NET_ACTIVE_WINDOW = - getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); _glfw.x11.NET_FRAME_EXTENTS = - getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); _glfw.x11.NET_REQUEST_FRAME_EXTENTS = - getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS"); + getAtomIfSupported(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS"); if (supportedAtoms) XFree(supportedAtoms); @@ -660,13 +766,12 @@ static GLFWbool initExtensions(void) _glfw.x11.xkb.detectable = GLFW_TRUE; } - _glfw.x11.xkb.group = 0; XkbStateRec state; if (XkbGetState(_glfw.x11.display, XkbUseCoreKbd, &state) == Success) - { - XkbSelectEventDetails(_glfw.x11.display, XkbUseCoreKbd, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupStateMask); _glfw.x11.xkb.group = (unsigned int)state.group; - } + + XkbSelectEventDetails(_glfw.x11.display, XkbUseCoreKbd, XkbStateNotify, + XkbGroupStateMask, XkbGroupStateMask); } #if defined(__CYGWIN__) @@ -851,6 +956,9 @@ static Window createHelperWindow(void) // static int errorHandler(Display *display, XErrorEvent* event) { + if (_glfw.x11.display != display) + return 0; + _glfw.x11.errorCode = event->error_code; return 0; } @@ -931,15 +1039,12 @@ Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) int _glfwPlatformInit(void) { -#if !defined(X_HAVE_UTF8_STRING) - // HACK: If the current locale is "C" and the Xlib UTF-8 functions are - // unavailable, apply the environment's locale in the hope that it's - // both available and not "C" - // This is done because the "C" locale breaks wide character input, - // which is what we fall back on when UTF-8 support is missing + // HACK: If the application has left the locale as "C" then both wide + // character text input and explicit UTF-8 input via XIM will break + // This sets the CTYPE part of the current locale from the environment + // in the hope that it is set to something more sane than "C" if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0) setlocale(LC_CTYPE, ""); -#endif XInitThreads(); XrmInitialize(); diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_monitor.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_monitor.c index 1f804ae..fb3a67b 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_monitor.c +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_monitor.c @@ -164,7 +164,7 @@ void _glfwPollMonitorsX11(void) if (widthMM <= 0 || heightMM <= 0) { // HACK: If RandR does not provide a physical size, assume the - // X11 default 96 DPI and calcuate from the CRTC viewport + // X11 default 96 DPI and calculate from the CRTC viewport // NOTE: These members are affected by rotation, unlike the mode // info and output info members widthMM = (int) (ci->width * 25.4f / 96.f); diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_platform.h b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_platform.h index 7377b2c..4873bd7 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_platform.h +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_platform.h @@ -199,8 +199,9 @@ typedef struct _GLFWwindowX11 // The last position the cursor was warped to by GLFW int warpCursorPosX, warpCursorPosY; - // The time of the last KeyPress event - Time lastKeyTime; + // The time of the last KeyPress event per keycode, for discarding + // duplicate key events generated for some keys by ibus + Time keyPressTimes[256]; } _GLFWwindowX11; diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_window.c b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_window.c index 271e108..90c4d9b 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_window.c +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw/src/x11_window.c @@ -1195,6 +1195,8 @@ static void processEvent(XEvent *event) { _glfw.x11.xkb.group = ((XkbEvent*) event)->state.group; } + + return; } } @@ -1273,16 +1275,20 @@ static void processEvent(XEvent *event) if (window->x11.ic) { - // HACK: Ignore duplicate key press events generated by ibus - // These have the same timestamp as the original event - // Corresponding release events are filtered out - // implicitly by the GLFW key repeat logic - if (window->x11.lastKeyTime < event->xkey.time) + // HACK: Do not report the key press events duplicated by XIM + // Duplicate key releases are filtered out implicitly by + // the GLFW key repeat logic in _glfwInputKey + // A timestamp per key is used to handle simultaneous keys + // NOTE: Always allow the first event for each key through + // (the server never sends a timestamp of zero) + // NOTE: Timestamp difference is compared to handle wrap-around + Time diff = event->xkey.time - window->x11.keyPressTimes[keycode]; + if (diff == event->xkey.time || (diff > 0 && diff < (1 << 31))) { if (keycode) _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); - window->x11.lastKeyTime = event->xkey.time; + window->x11.keyPressTimes[keycode] = event->xkey.time; } if (!filtered) @@ -1557,6 +1563,8 @@ static void processEvent(XEvent *event) // the position into root (screen) coordinates if (!event->xany.send_event && window->x11.parent != _glfw.x11.root) { + _glfwGrabErrorHandlerX11(); + Window dummy; XTranslateCoordinates(_glfw.x11.display, window->x11.parent, @@ -1564,6 +1572,10 @@ static void processEvent(XEvent *event) xpos, ypos, &xpos, &ypos, &dummy); + + _glfwReleaseErrorHandlerX11(); + if (_glfw.x11.errorCode == BadWindow) + return; } if (xpos != window->x11.xpos || ypos != window->x11.ypos) @@ -1971,7 +1983,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { - Visual* visual; + Visual* visual = NULL; int depth; if (ctxconfig->client != GLFW_NO_API) @@ -1997,8 +2009,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, } } - if (ctxconfig->client == GLFW_NO_API || - ctxconfig->source == GLFW_OSMESA_CONTEXT_API) + if (!visual) { visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen); depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen); @@ -2580,13 +2591,19 @@ int _glfwPlatformWindowHovered(_GLFWwindow* window) int rootX, rootY, childX, childY; unsigned int mask; - if (!XQueryPointer(_glfw.x11.display, w, - &root, &w, &rootX, &rootY, &childX, &childY, &mask)) - { - return GLFW_FALSE; - } + _glfwGrabErrorHandlerX11(); + + const Bool result = XQueryPointer(_glfw.x11.display, w, + &root, &w, &rootX, &rootY, + &childX, &childY, &mask); - if (w == window->x11.handle) + _glfwReleaseErrorHandlerX11(); + + if (_glfw.x11.errorCode == BadWindow) + w = _glfw.x11.root; + else if (!result) + return GLFW_FALSE; + else if (w == window->x11.handle) return GLFW_TRUE; } @@ -2950,8 +2967,9 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) void _glfwPlatformSetClipboardString(const char* string) { + char* copy = _glfw_strdup(string); free(_glfw.x11.clipboardString); - _glfw.x11.clipboardString = _glfw_strdup(string); + _glfw.x11.clipboardString = copy; XSetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD, diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw_tree_rebuild.go b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw_tree_rebuild.go new file mode 100644 index 0000000..22ff028 --- /dev/null +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/glfw_tree_rebuild.go @@ -0,0 +1,10 @@ +package glfw + +//go:generate ../../scripts/glfw_tree_rebuild.sh + +// upstreamTreeSHA is a recursive hash of the full contents of the upstream +// glfw, as generated by git (doesn't need to be committed) when you run `go +// generate` on this package. This exists to invalidate the build cache (see +// https://github.com/go-gl/glfw/issues/269), which is unaffected by C source +// inputs. +const upstreamTreeSHA = "4490c2c270a92046291b021c15e33340289b33db" diff --git a/vendor/github.com/go-gl/glfw/v3.3/glfw/util.go b/vendor/github.com/go-gl/glfw/v3.3/glfw/util.go index 0d0a2c9..2bf56ed 100644 --- a/vendor/github.com/go-gl/glfw/v3.3/glfw/util.go +++ b/vendor/github.com/go-gl/glfw/v3.3/glfw/util.go @@ -5,11 +5,6 @@ package glfw //#include "glfw/include/GLFW/glfw3.h" import "C" -import ( - "reflect" - "unsafe" -) - func glfwbool(b C.int) bool { if b == C.int(True) { return true @@ -19,20 +14,10 @@ func glfwbool(b C.int) bool { func bytes(origin []byte) (pointer *uint8, free func()) { n := len(origin) - if n == 0 { return nil, func() {} } - data := C.malloc(C.size_t(n)) - - dataSlice := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(data), - Len: n, - Cap: n, - })) - - copy(dataSlice, origin) - - return &dataSlice[0], func() { C.free(data) } + ptr := C.CBytes(origin) + return (*uint8)(ptr), func() { C.free(ptr) } } diff --git a/vendor/github.com/golang/protobuf/proto/registry.go b/vendor/github.com/golang/protobuf/proto/registry.go index 1e7ff64..066b432 100644 --- a/vendor/github.com/golang/protobuf/proto/registry.go +++ b/vendor/github.com/golang/protobuf/proto/registry.go @@ -13,6 +13,7 @@ import ( "strings" "sync" + "google.golang.org/protobuf/reflect/protodesc" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" "google.golang.org/protobuf/runtime/protoimpl" @@ -62,14 +63,7 @@ func FileDescriptor(s filePath) fileDescGZIP { // Find the descriptor in the v2 registry. var b []byte if fd, _ := protoregistry.GlobalFiles.FindFileByPath(s); fd != nil { - if fd, ok := fd.(interface{ ProtoLegacyRawDesc() []byte }); ok { - b = fd.ProtoLegacyRawDesc() - } else { - // TODO: Use protodesc.ToFileDescriptorProto to construct - // a descriptorpb.FileDescriptorProto and marshal it. - // However, doing so causes the proto package to have a dependency - // on descriptorpb, leading to cyclic dependency issues. - } + b, _ = Marshal(protodesc.ToFileDescriptorProto(fd)) } // Locally cache the raw descriptor form for the file. diff --git a/vendor/golang.org/x/image/vector/acc_amd64.go b/vendor/golang.org/x/image/vector/acc_amd64.go index c0d6ad9..a6fa0ca 100644 --- a/vendor/golang.org/x/image/vector/acc_amd64.go +++ b/vendor/golang.org/x/image/vector/acc_amd64.go @@ -2,9 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !appengine -// +build gc -// +build !noasm +//go:build !appengine && gc && !noasm +// +build !appengine,gc,!noasm package vector diff --git a/vendor/golang.org/x/image/vector/acc_other.go b/vendor/golang.org/x/image/vector/acc_other.go index d00bed8..3902269 100644 --- a/vendor/golang.org/x/image/vector/acc_other.go +++ b/vendor/golang.org/x/image/vector/acc_other.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !amd64 || appengine || !gc || noasm // +build !amd64 appengine !gc noasm package vector diff --git a/vendor/golang.org/x/net/html/const.go b/vendor/golang.org/x/net/html/const.go index 73804d3..ff7acf2 100644 --- a/vendor/golang.org/x/net/html/const.go +++ b/vendor/golang.org/x/net/html/const.go @@ -52,7 +52,7 @@ var isSpecialElementMap = map[string]bool{ "iframe": true, "img": true, "input": true, - "keygen": true, + "keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility. "li": true, "link": true, "listing": true, diff --git a/vendor/golang.org/x/net/html/foreign.go b/vendor/golang.org/x/net/html/foreign.go index 74774c4..9da9e9d 100644 --- a/vendor/golang.org/x/net/html/foreign.go +++ b/vendor/golang.org/x/net/html/foreign.go @@ -161,65 +161,62 @@ var mathMLAttributeAdjustments = map[string]string{ } var svgAttributeAdjustments = map[string]string{ - "attributename": "attributeName", - "attributetype": "attributeType", - "basefrequency": "baseFrequency", - "baseprofile": "baseProfile", - "calcmode": "calcMode", - "clippathunits": "clipPathUnits", - "contentscripttype": "contentScriptType", - "contentstyletype": "contentStyleType", - "diffuseconstant": "diffuseConstant", - "edgemode": "edgeMode", - "externalresourcesrequired": "externalResourcesRequired", - "filterunits": "filterUnits", - "glyphref": "glyphRef", - "gradienttransform": "gradientTransform", - "gradientunits": "gradientUnits", - "kernelmatrix": "kernelMatrix", - "kernelunitlength": "kernelUnitLength", - "keypoints": "keyPoints", - "keysplines": "keySplines", - "keytimes": "keyTimes", - "lengthadjust": "lengthAdjust", - "limitingconeangle": "limitingConeAngle", - "markerheight": "markerHeight", - "markerunits": "markerUnits", - "markerwidth": "markerWidth", - "maskcontentunits": "maskContentUnits", - "maskunits": "maskUnits", - "numoctaves": "numOctaves", - "pathlength": "pathLength", - "patterncontentunits": "patternContentUnits", - "patterntransform": "patternTransform", - "patternunits": "patternUnits", - "pointsatx": "pointsAtX", - "pointsaty": "pointsAtY", - "pointsatz": "pointsAtZ", - "preservealpha": "preserveAlpha", - "preserveaspectratio": "preserveAspectRatio", - "primitiveunits": "primitiveUnits", - "refx": "refX", - "refy": "refY", - "repeatcount": "repeatCount", - "repeatdur": "repeatDur", - "requiredextensions": "requiredExtensions", - "requiredfeatures": "requiredFeatures", - "specularconstant": "specularConstant", - "specularexponent": "specularExponent", - "spreadmethod": "spreadMethod", - "startoffset": "startOffset", - "stddeviation": "stdDeviation", - "stitchtiles": "stitchTiles", - "surfacescale": "surfaceScale", - "systemlanguage": "systemLanguage", - "tablevalues": "tableValues", - "targetx": "targetX", - "targety": "targetY", - "textlength": "textLength", - "viewbox": "viewBox", - "viewtarget": "viewTarget", - "xchannelselector": "xChannelSelector", - "ychannelselector": "yChannelSelector", - "zoomandpan": "zoomAndPan", + "attributename": "attributeName", + "attributetype": "attributeType", + "basefrequency": "baseFrequency", + "baseprofile": "baseProfile", + "calcmode": "calcMode", + "clippathunits": "clipPathUnits", + "diffuseconstant": "diffuseConstant", + "edgemode": "edgeMode", + "filterunits": "filterUnits", + "glyphref": "glyphRef", + "gradienttransform": "gradientTransform", + "gradientunits": "gradientUnits", + "kernelmatrix": "kernelMatrix", + "kernelunitlength": "kernelUnitLength", + "keypoints": "keyPoints", + "keysplines": "keySplines", + "keytimes": "keyTimes", + "lengthadjust": "lengthAdjust", + "limitingconeangle": "limitingConeAngle", + "markerheight": "markerHeight", + "markerunits": "markerUnits", + "markerwidth": "markerWidth", + "maskcontentunits": "maskContentUnits", + "maskunits": "maskUnits", + "numoctaves": "numOctaves", + "pathlength": "pathLength", + "patterncontentunits": "patternContentUnits", + "patterntransform": "patternTransform", + "patternunits": "patternUnits", + "pointsatx": "pointsAtX", + "pointsaty": "pointsAtY", + "pointsatz": "pointsAtZ", + "preservealpha": "preserveAlpha", + "preserveaspectratio": "preserveAspectRatio", + "primitiveunits": "primitiveUnits", + "refx": "refX", + "refy": "refY", + "repeatcount": "repeatCount", + "repeatdur": "repeatDur", + "requiredextensions": "requiredExtensions", + "requiredfeatures": "requiredFeatures", + "specularconstant": "specularConstant", + "specularexponent": "specularExponent", + "spreadmethod": "spreadMethod", + "startoffset": "startOffset", + "stddeviation": "stdDeviation", + "stitchtiles": "stitchTiles", + "surfacescale": "surfaceScale", + "systemlanguage": "systemLanguage", + "tablevalues": "tableValues", + "targetx": "targetX", + "targety": "targetY", + "textlength": "textLength", + "viewbox": "viewBox", + "viewtarget": "viewTarget", + "xchannelselector": "xChannelSelector", + "ychannelselector": "yChannelSelector", + "zoomandpan": "zoomAndPan", } diff --git a/vendor/golang.org/x/net/html/parse.go b/vendor/golang.org/x/net/html/parse.go index 2cd12fc..f91466f 100644 --- a/vendor/golang.org/x/net/html/parse.go +++ b/vendor/golang.org/x/net/html/parse.go @@ -728,7 +728,13 @@ func inHeadNoscriptIM(p *parser) bool { return inBodyIM(p) case a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Style: return inHeadIM(p) - case a.Head, a.Noscript: + case a.Head: + // Ignore the token. + return true + case a.Noscript: + // Don't let the tokenizer go into raw text mode even when a