app: add shiny backend

Combined with the outstanding shiny CLs and prebuilt ANGLE dlls in the
right place, this makes it possible to run example/basic on a windows
machine.

Eventually this shiny backend will also replace the app package's
custom darwin_amd64 and linux_x11 backends.

For golang/go#9306

Change-Id: Ia4bf9a85b9d903d79cee36abb470a0ad57f09f36
Reviewed-on: https://go-review.googlesource.com/17777
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/app/app.go b/app/app.go
index 720dba4..fdcb4d0 100644
--- a/app/app.go
+++ b/app/app.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build linux darwin
+// +build linux darwin windows
 
 package app
 
diff --git a/app/shiny.go b/app/shiny.go
new file mode 100644
index 0000000..56f28e8
--- /dev/null
+++ b/app/shiny.go
@@ -0,0 +1,70 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package app
+
+import (
+	"log"
+
+	"golang.org/x/exp/shiny/driver/gldriver"
+	"golang.org/x/exp/shiny/screen"
+	"golang.org/x/mobile/event/lifecycle"
+	"golang.org/x/mobile/event/mouse"
+	"golang.org/x/mobile/event/touch"
+	"golang.org/x/mobile/gl"
+)
+
+func main(f func(a App)) {
+	gldriver.Main(func(s screen.Screen) {
+		w, err := s.NewWindow(nil)
+		if err != nil {
+			log.Fatal(err)
+		}
+		defer w.Release()
+
+		theApp.glctx = nil
+		theApp.worker = nil // handled by shiny
+
+		go func() {
+			for range theApp.publish {
+				res := w.Publish()
+				theApp.publishResult <- PublishResult{
+					BackBufferPreserved: res.BackBufferPreserved,
+				}
+			}
+		}()
+
+		go f(theApp)
+
+		for e := range w.Events() {
+			theApp.Send(convertEvent(e))
+		}
+	})
+}
+
+func convertEvent(e interface{}) interface{} {
+	switch e := e.(type) {
+	case lifecycle.Event:
+		if theApp.glctx == nil {
+			theApp.glctx = e.DrawContext.(gl.Context)
+		}
+	case mouse.Event:
+		te := touch.Event{
+			X: e.X,
+			Y: e.Y,
+		}
+		switch e.Direction {
+		case mouse.DirNone:
+			te.Type = touch.TypeMove
+		case mouse.DirPress:
+			te.Type = touch.TypeBegin
+		case mouse.DirRelease:
+			te.Type = touch.TypeEnd
+		}
+		return te
+	}
+	return e
+}