summaryrefslogtreecommitdiff
path: root/redo/uitask.go
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-08-18 16:52:20 -0400
committerPietro Gagliardi <[email protected]>2014-08-18 16:52:20 -0400
commit7c13661f4adeb2b8cc2e4609f46bd0609c8da30f (patch)
tree725e2227ec8de345b23e18f513d66456546006b7 /redo/uitask.go
parent570f08a49ce1099cee4feed9ae006b3f0545b7a0 (diff)
Added foreign events. Untested for now.
Diffstat (limited to 'redo/uitask.go')
-rw-r--r--redo/uitask.go51
1 files changed, 51 insertions, 0 deletions
diff --git a/redo/uitask.go b/redo/uitask.go
index 4460ab2..3580278 100644
--- a/redo/uitask.go
+++ b/redo/uitask.go
@@ -6,6 +6,7 @@ import (
"runtime"
"sync"
"unsafe"
+ "reflect"
)
// Go initializes and runs package ui.
@@ -115,3 +116,53 @@ func perform(fp unsafe.Pointer) {
f := (*func())(fp)
(*f)()
}
+
+// ForeignEvent wraps a channel in such a way that it can be used safely with package ui.
+type ForeignEvent struct {
+ c reflect.Value
+ e *event
+ d interface{}
+}
+
+// NewForeignEvent creates a new ForeignEvent with the specified channel.
+// It panics if the argument is not a receivable channel.
+// The returned ForeignEvent assumes ownership of the channel.
+// Each time a value is received on the channel, the returned function is invoked on the main thread.
+func NewForeignEvent(channel interface{}, handler func(data interface{})) *ForeignEvent {
+ c := reflect.ValueOf(channel)
+ t := c.Type()
+ if t.Kind() != reflect.Chan || (t.ChanDir() & reflect.RecvDir) == 0 {
+ panic("non-channel or non-receivable channel passed to NewForeignEvent()")
+ }
+ fe := &ForeignEvent{
+ c: c,
+ e: newEvent(),
+ }
+ fe.e.set(func() {
+ handler(fe.d)
+ })
+ go fe.do()
+ return fe
+}
+
+func (fe *ForeignEvent) do() {
+ wait := make(chan struct{})
+ defer close(wait)
+ for {
+ v, ok := fe.c.Recv()
+ if !ok {
+ break
+ }
+ fe.d = v.Interface()
+ Do(func() {
+ fe.e.fire()
+ wait <- struct{}{}
+ })
+ <-wait
+ }
+}
+
+// Stop ceases all future invocations of the handler passed to NewForeignEvent() on fe; the values read from the channel are merely discarded.
+func (fe *ForeignEvent) Stop() {
+ fe.e.set(nil)
+}