Removed Request completely, also updating the uitask files. Also renamed xperform to doissue for consistency.
This commit is contained in:
parent
48c5055eb9
commit
104337188f
|
@ -1,69 +0,0 @@
|
|||
// 6 july 2014
|
||||
|
||||
package ui
|
||||
|
||||
// Doer is a channel that takes Requests returned by the various functions and methods of package ui.
|
||||
// There are two main Doers: ui.Do, which is for outside event handlers, and the Doer passed into an event handler function.
|
||||
// You should not create or use your own Doers; these are meaningless.
|
||||
type Doer chan *Request
|
||||
|
||||
// Do is the main way to issue requests to package ui.
|
||||
// Requests returned by the various functions and methods of package ui should be sent across Do to have them performed.
|
||||
// When an event is dispatched to an event handler, that event handler will receive a new Doer which is active for the life of the event handler, and any requests made to Do will block until the event handler returns.
|
||||
var Do = make(Doer)
|
||||
|
||||
// Request represents a request issued to the package.
|
||||
// These are returned by the various functions and methods of package ui and are sent to either Do or to the currently active event handler channel.
|
||||
// There are also several convenience functions that perfrom common operations with requests.
|
||||
type Request struct {
|
||||
op func()
|
||||
resp chan interface{}
|
||||
}
|
||||
|
||||
// Response returns a channel which is pulsed exactly once, then immeidately closed, with the response from the function that issued the request.
|
||||
// If the function does not return a value, this value will be the zero value of struct{}.
|
||||
// Otherwise, the type of this value depends on the function that created the Request.
|
||||
func (r *Request) Response() <-chan interface{} {
|
||||
return r.resp
|
||||
}
|
||||
|
||||
// Wait is a convenience function that performs a Request and waits for that request to be processed.
|
||||
// If the request returns a value, it is discarded.
|
||||
// You should generally use Wait on functions that do not return a value.
|
||||
// See the documentation of Bool for an example.
|
||||
func Wait(c Doer, r *Request) {
|
||||
c <- r
|
||||
<-r.resp
|
||||
}
|
||||
|
||||
// Bool is a convenience function that performs a Request that returns a bool, waits for that request to be processed, and returns the result.
|
||||
// For example:
|
||||
// if ui.Bool(ui.Do, checkbox.Checked()) { /* do stuff */ }
|
||||
func Bool(c Doer, r *Request) bool {
|
||||
c <- r
|
||||
return (<-r.resp).(bool)
|
||||
}
|
||||
|
||||
// Int is like Bool, but for int.
|
||||
func Int(c Doer, r *Request) int {
|
||||
c <- r
|
||||
return (<-r.resp).(int)
|
||||
}
|
||||
|
||||
// String is like Bool, but for string.
|
||||
func String(c Doer, r *Request) string {
|
||||
c <- r
|
||||
return (<-r.resp).(string)
|
||||
}
|
||||
|
||||
// IntSlice is like Bool, but for []int.
|
||||
func IntSlice(c Doer, r *Request) []int {
|
||||
c <- r
|
||||
return (<-r.resp).([]int)
|
||||
}
|
||||
|
||||
// StringSlice is like Bool, but for []string.
|
||||
func StringSlice(c Doer, r *Request) []string {
|
||||
c <- r
|
||||
return (<-r.resp).([]string)
|
||||
}
|
|
@ -14,53 +14,32 @@ func Go() error {
|
|||
if err := uiinit(); err != nil {
|
||||
return err
|
||||
}
|
||||
go uitask(Do)
|
||||
uimsgloop()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop issues a Request for package ui to stop and returns immediately.
|
||||
// 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)
|
||||
issue(func() {
|
||||
f()
|
||||
done <- struct{}{}
|
||||
})
|
||||
<-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 is internally issued to Do, so it will not be registered until any event handlers and dialog boxes return.
|
||||
// Stop will not have an effect until any event handlers or dialog boxes presently active return.
|
||||
// (TODO make sure this is the case for dialog boxes)
|
||||
func Stop() {
|
||||
go func() {
|
||||
c := make(chan interface{})
|
||||
Do <- &Request{
|
||||
op: func() {
|
||||
uistop()
|
||||
c <- struct{}{}
|
||||
},
|
||||
resp: c,
|
||||
}
|
||||
<-c
|
||||
}()
|
||||
issue(uistop)
|
||||
}
|
||||
|
||||
// This is the ui main loop.
|
||||
// It is spawned by Go as a goroutine.
|
||||
// It can also be called recursively using the recur/unrecur chain.
|
||||
func uitask(doer Doer) {
|
||||
for {
|
||||
select {
|
||||
case req := <-doer:
|
||||
// TODO foreign event
|
||||
issue(req)
|
||||
case rec := <-recur: // want to perform event
|
||||
c := make(Doer)
|
||||
rec <- c
|
||||
uitask(c)
|
||||
case <-unrecur: // finished with event
|
||||
close(doer)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send a channel over recur to have uitask() above enter a recursive loop in which the Doer sent back becomes the active request handler.
|
||||
// Pulse unrecur when finished.
|
||||
var recur = make(chan chan Doer)
|
||||
var unrecur = make(chan struct{})
|
||||
|
||||
type event struct {
|
||||
// All events internally return bool; those that don't will be wrapped around to return a dummy value.
|
||||
do func(c Doer) bool
|
||||
|
@ -105,38 +84,16 @@ func (e *event) setbool(f func(Doer) bool) {
|
|||
// 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 {
|
||||
cc := make(chan Doer)
|
||||
recur <- cc
|
||||
c := <-cc
|
||||
close(cc)
|
||||
result := false
|
||||
finished := make(chan struct{})
|
||||
go func() {
|
||||
e.lock.Lock()
|
||||
defer e.lock.Unlock()
|
||||
|
||||
result = e.do(c)
|
||||
finished <- struct{}{}
|
||||
}()
|
||||
<-finished
|
||||
close(finished)
|
||||
// leave the event handler; leave it only after returning from the OS-side event handler so we must issue it like a normal Request
|
||||
issue(&Request{
|
||||
op: func() {
|
||||
unrecur <- struct{}{}
|
||||
},
|
||||
// unfortunately, closing a nil channel causes a panic
|
||||
// therefore, we have to make a dummy channel
|
||||
// TODO add conditional checks to the request handler instead?
|
||||
resp: make(chan interface{}),
|
||||
})
|
||||
return result
|
||||
return e.do(c)
|
||||
}
|
||||
|
||||
// Common code for performing a Request.
|
||||
// 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(req *Request) {
|
||||
req.op()
|
||||
close(req.resp)
|
||||
func perform(fp unsafe.Pointer) {
|
||||
f := (*func())(fp)
|
||||
(*f)()
|
||||
}
|
||||
|
|
|
@ -25,12 +25,11 @@ func uistop() {
|
|||
C.uistop()
|
||||
}
|
||||
|
||||
func issue(req *Request) {
|
||||
C.issue(unsafe.Pointer(req))
|
||||
func issue(f func()) {
|
||||
C.issue(unsafe.Pointer(&f))
|
||||
}
|
||||
|
||||
//export doissue
|
||||
func doissue(r unsafe.Pointer) {
|
||||
req := (*Request)(unsafe.Pointer(r))
|
||||
perform(req)
|
||||
func doissue(fp unsafe.Pointer) {
|
||||
perform(fp)
|
||||
}
|
||||
|
|
|
@ -27,13 +27,12 @@ func uistop() {
|
|||
C.gtk_main_quit()
|
||||
}
|
||||
|
||||
func issue(req *Request) {
|
||||
C.gdk_threads_add_idle(C.GSourceFunc(C.doissue), C.gpointer(unsafe.Pointer(req)))
|
||||
func issue(f func()) {
|
||||
C.gdk_threads_add_idle(C.GSourceFunc(C.doissue), C.gpointer(unsafe.Pointer(&f)))
|
||||
}
|
||||
|
||||
//export doissue
|
||||
func doissue(data C.gpointer) C.gboolean {
|
||||
req := (*Request)(unsafe.Pointer(data))
|
||||
perform(req)
|
||||
perform(unsafe.Pointer(data))
|
||||
return C.FALSE // don't repeat
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ static LRESULT CALLBACK msgwinproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l
|
|||
case WM_COMMAND:
|
||||
return forwardCommand(hwnd, uMsg, wParam, lParam);
|
||||
case msgRequest:
|
||||
xperform((void *) lParam);
|
||||
doissue((void *) lParam);
|
||||
return 0;
|
||||
default:
|
||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||
|
|
|
@ -41,8 +41,8 @@ func uistop() {
|
|||
C.PostQuitMessage(0)
|
||||
}
|
||||
|
||||
func issue(req *Request) {
|
||||
C.issue(unsafe.Pointer(req))
|
||||
func issue(f func()) {
|
||||
C.issue(unsafe.Pointer(&f))
|
||||
}
|
||||
|
||||
func makemsgwin() error {
|
||||
|
@ -55,8 +55,7 @@ func makemsgwin() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//export xperform
|
||||
func xperform(xreq unsafe.Pointer) {
|
||||
req := (*Request)(xreq)
|
||||
perform(req)
|
||||
//export doissue
|
||||
func doissue(fp unsafe.Pointer) {
|
||||
perform(fp)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue