summaryrefslogtreecommitdiff
path: root/uitask.go
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2015-12-11 20:37:59 -0500
committerPietro Gagliardi <[email protected]>2015-12-11 20:37:59 -0500
commitf8e3f12ab02b528f2a05a4f713d7af7ea8e44b42 (patch)
tree82dedf4d37f0f6d31e88ebb2ca1ce6499dead261 /uitask.go
parente34c561ed5bedeb180437ec165882b98d70d38c1 (diff)
LET'S GET THIS FINAL REWRITE EVER STARTED
Diffstat (limited to 'uitask.go')
-rw-r--r--uitask.go164
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)
-}