blob: c7faea2009d8757bd7666c1c5658d1776d49780b (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
// 6 july 2014
package ui
import (
"runtime"
"sync"
"unsafe"
)
// Go initializes package ui.
// TODO write this bit
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.
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)
issuer <- 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 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() {
issuer <- 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
}
// do should never be nil; TODO should we make setters panic instead?
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)()
}
|