diff options
| author | Pietro Gagliardi <[email protected]> | 2015-12-11 20:37:59 -0500 |
|---|---|---|
| committer | Pietro Gagliardi <[email protected]> | 2015-12-11 20:37:59 -0500 |
| commit | f8e3f12ab02b528f2a05a4f713d7af7ea8e44b42 (patch) | |
| tree | 82dedf4d37f0f6d31e88ebb2ca1ce6499dead261 /uitask.go | |
| parent | e34c561ed5bedeb180437ec165882b98d70d38c1 (diff) | |
LET'S GET THIS FINAL REWRITE EVER STARTED
Diffstat (limited to 'uitask.go')
| -rw-r--r-- | uitask.go | 164 |
1 files changed, 0 insertions, 164 deletions
diff --git a/uitask.go b/uitask.go deleted file mode 100644 index 0d16f8a..0000000 --- a/uitask.go +++ /dev/null @@ -1,164 +0,0 @@ -// 6 july 2014 - -package ui - -import ( - "reflect" - "runtime" - "sync" - "unsafe" -) - -// Go initializes and runs package ui. -// It returns a non-nil error if initialization fails. -// Otherwise, it will run the event loop and not return until Stop is called. -// Due to platform-specific issues, it must be called from the main OS thread; in general, do not call Go() from anywhere except main() (including any goroutines). -func Go() error { - runtime.LockOSThread() - if err := uiinit(); err != nil { - return err - } - go uiissueloop() - uimsgloop() - return nil -} - -// To ensure that Do() and Stop() only do things after Go() has been called, this channel accepts the requests to issue. The issuing is done by uiissueloop() below. -// Notice that this is a pointer ot a function. See Do() below for details. -var issuer = make(chan *func()) - -// Do performs f on the main loop, as if it were an event handler. -// It waits for f to execute before returning. -// Do cannot be called within event handlers or within Do itself. -func Do(f func()) { - done := make(chan struct{}) - defer close(done) - // THIS MUST BE A POINTER. - // Previously, the pointer was constructed within issue(). - // This meant that if the Do() was stalled, the garbage collector came in and reused the pointer value too soon! - call := func() { - f() - done <- struct{}{} - } - issuer <- &call - <-done -} - -// Stop informs package ui that it should stop. -// Stop then returns immediately. -// Some time after this request is received, Go() will return without performing any final cleanup. -// Stop will not have an effect until any event handlers return. -func Stop() { - // can't send this directly across issuer - go func() { - Do(uistop) - }() -} - -func uiissueloop() { - for f := range issuer { - issue(f) - } -} - -type event struct { - // All events internally return bool; those that don't will be wrapped around to return a dummy value. - do func() bool - lock sync.Mutex -} - -func newEvent() *event { - return &event{ - do: func() bool { - return false - }, - } -} - -func (e *event) set(f func()) { - e.lock.Lock() - defer e.lock.Unlock() - - if f == nil { - f = func() {} - } - e.do = func() bool { - f() - return false - } -} - -func (e *event) setbool(f func() bool) { - e.lock.Lock() - defer e.lock.Unlock() - - if f == nil { - f = func() bool { - return false - } - } - e.do = f -} - -// This is the common code for running an event. -// It runs on the main thread without a message pump; it provides its own. -func (e *event) fire() bool { - e.lock.Lock() - defer e.lock.Unlock() - - return e.do() -} - -// Common code for performing a requested action (ui.Do() or ui.Stop()). -// This should run on the main thread. -// Implementations of issue() should call this. -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() { - for { - v, ok := fe.c.Recv() - if !ok { - break - } - fe.d = v.Interface() - Do(func() { - fe.e.fire() - }) - } -} - -// 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) -} |
