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 {
|
if err := uiinit(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
go uitask(Do)
|
|
||||||
uimsgloop()
|
uimsgloop()
|
||||||
return nil
|
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.
|
// 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() {
|
func Stop() {
|
||||||
go func() {
|
issue(uistop)
|
||||||
c := make(chan interface{})
|
|
||||||
Do <- &Request{
|
|
||||||
op: func() {
|
|
||||||
uistop()
|
|
||||||
c <- struct{}{}
|
|
||||||
},
|
|
||||||
resp: c,
|
|
||||||
}
|
|
||||||
<-c
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
type event struct {
|
||||||
// All events internally return bool; those that don't will be wrapped around to return a dummy value.
|
// All events internally return bool; those that don't will be wrapped around to return a dummy value.
|
||||||
do func(c Doer) bool
|
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.
|
// This is the common code for running an event.
|
||||||
// It runs on the main thread without a message pump; it provides its own.
|
// It runs on the main thread without a message pump; it provides its own.
|
||||||
func (e *event) fire() bool {
|
func (e *event) fire() bool {
|
||||||
cc := make(chan Doer)
|
e.lock.Lock()
|
||||||
recur <- cc
|
defer e.lock.Unlock()
|
||||||
c := <-cc
|
|
||||||
close(cc)
|
|
||||||
result := false
|
|
||||||
finished := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
e.lock.Lock()
|
|
||||||
defer e.lock.Unlock()
|
|
||||||
|
|
||||||
result = e.do(c)
|
return 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
// This should run on the main thread.
|
||||||
// Implementations of issue() should call this.
|
// Implementations of issue() should call this.
|
||||||
func perform(req *Request) {
|
func perform(fp unsafe.Pointer) {
|
||||||
req.op()
|
f := (*func())(fp)
|
||||||
close(req.resp)
|
(*f)()
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,11 @@ func uistop() {
|
||||||
C.uistop()
|
C.uistop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func issue(req *Request) {
|
func issue(f func()) {
|
||||||
C.issue(unsafe.Pointer(req))
|
C.issue(unsafe.Pointer(&f))
|
||||||
}
|
}
|
||||||
|
|
||||||
//export doissue
|
//export doissue
|
||||||
func doissue(r unsafe.Pointer) {
|
func doissue(fp unsafe.Pointer) {
|
||||||
req := (*Request)(unsafe.Pointer(r))
|
perform(fp)
|
||||||
perform(req)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,13 +27,12 @@ func uistop() {
|
||||||
C.gtk_main_quit()
|
C.gtk_main_quit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func issue(req *Request) {
|
func issue(f func()) {
|
||||||
C.gdk_threads_add_idle(C.GSourceFunc(C.doissue), C.gpointer(unsafe.Pointer(req)))
|
C.gdk_threads_add_idle(C.GSourceFunc(C.doissue), C.gpointer(unsafe.Pointer(&f)))
|
||||||
}
|
}
|
||||||
|
|
||||||
//export doissue
|
//export doissue
|
||||||
func doissue(data C.gpointer) C.gboolean {
|
func doissue(data C.gpointer) C.gboolean {
|
||||||
req := (*Request)(unsafe.Pointer(data))
|
perform(unsafe.Pointer(data))
|
||||||
perform(req)
|
|
||||||
return C.FALSE // don't repeat
|
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:
|
case WM_COMMAND:
|
||||||
return forwardCommand(hwnd, uMsg, wParam, lParam);
|
return forwardCommand(hwnd, uMsg, wParam, lParam);
|
||||||
case msgRequest:
|
case msgRequest:
|
||||||
xperform((void *) lParam);
|
doissue((void *) lParam);
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||||
|
|
|
@ -41,8 +41,8 @@ func uistop() {
|
||||||
C.PostQuitMessage(0)
|
C.PostQuitMessage(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func issue(req *Request) {
|
func issue(f func()) {
|
||||||
C.issue(unsafe.Pointer(req))
|
C.issue(unsafe.Pointer(&f))
|
||||||
}
|
}
|
||||||
|
|
||||||
func makemsgwin() error {
|
func makemsgwin() error {
|
||||||
|
@ -55,8 +55,7 @@ func makemsgwin() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//export xperform
|
//export doissue
|
||||||
func xperform(xreq unsafe.Pointer) {
|
func doissue(fp unsafe.Pointer) {
|
||||||
req := (*Request)(xreq)
|
perform(fp)
|
||||||
perform(req)
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue