diff options
| author | Pietro Gagliardi <[email protected]> | 2014-08-18 16:52:20 -0400 |
|---|---|---|
| committer | Pietro Gagliardi <[email protected]> | 2014-08-18 16:52:20 -0400 |
| commit | 7c13661f4adeb2b8cc2e4609f46bd0609c8da30f (patch) | |
| tree | 725e2227ec8de345b23e18f513d66456546006b7 /redo/uitask.go | |
| parent | 570f08a49ce1099cee4feed9ae006b3f0545b7a0 (diff) | |
Added foreign events. Untested for now.
Diffstat (limited to 'redo/uitask.go')
| -rw-r--r-- | redo/uitask.go | 51 |
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) +} |
