summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--stdwndclass_windows.go4
-rw-r--r--sysdata.go5
-rw-r--r--test/main.go7
-rw-r--r--uitask.go8
-rw-r--r--uitask_windows.go10
-rw-r--r--window.go9
6 files changed, 38 insertions, 5 deletions
diff --git a/stdwndclass_windows.go b/stdwndclass_windows.go
index f6dd395..ef6a053 100644
--- a/stdwndclass_windows.go
+++ b/stdwndclass_windows.go
@@ -108,6 +108,10 @@ func stdWndProc(hwnd _HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM) _LRESUL
return storeSysData(hwnd, uMsg, wParam, lParam)
}
switch uMsg {
+ case msgPost:
+ data := (*interface{})(unsafe.Pointer(lParam))
+ s.post(*data)
+ return 0
case _WM_COMMAND:
id := _HMENU(wParam.LOWORD())
s.childrenLock.Lock()
diff --git a/sysdata.go b/sysdata.go
index 006595c..ccd5935 100644
--- a/sysdata.go
+++ b/sysdata.go
@@ -9,8 +9,9 @@ type cSysData struct {
spaced bool
alternate bool // editable for Combobox, multi-select for listbox, password for lineedit
handler AreaHandler // for Areas; TODO rename to areahandler
- close func() bool // provided by each Window
- event func() // provided by each control
+ close func() bool // provided by each Window
+ post func(interface{}) // provided by each Window
+ event func() // provided by each control
}
// this interface is used to make sure all sysDatas are synced
diff --git a/test/main.go b/test/main.go
index da6a8eb..7f5d656 100644
--- a/test/main.go
+++ b/test/main.go
@@ -249,12 +249,13 @@ func areaTest() {
layout.SetStretchy(0)
w := NewWindow("Area Test", 100, 100)
w.Closing = die
+ w.Posted = func(data interface{}) {
+ timedisp.SetText(data.(string))
+ }
w.Open(layout)
go func() {
for t := range timechan {
- // TODO
- _ = t
-// timedisp.SetText(t.String())
+ Post(w, t.String())
}
}()
}
diff --git a/uitask.go b/uitask.go
index fceab1b..40fe003 100644
--- a/uitask.go
+++ b/uitask.go
@@ -26,6 +26,14 @@ func Go(start func()) error {
return nil
}
+// Post issues a request to the given Window to do something on the main thread.
+// Note the name of the function: there is no guarantee that the request will be handled immediately.
+// Because this can be safely called from any goroutine, it is a package-level function, and not a method on Window.
+// TODO garbage collection
+func Post(w *Window, data interface{}) {
+ uipost(w, data)
+}
+
// TODO this needs to be replaced with a function
// Stop should be pulsed when you are ready for Go() to return.
// Pulsing Stop will cause Go() to return immediately; the programmer is responsible for cleaning up (for instance, hiding open Windows) beforehand.
diff --git a/uitask_windows.go b/uitask_windows.go
index f260e79..ca00d3a 100644
--- a/uitask_windows.go
+++ b/uitask_windows.go
@@ -29,6 +29,7 @@ const (
msgQuit = _WM_APP + iota + 1 // + 1 just to be safe
msgSetAreaSize
msgRepaintAll
+ msgPost
)
func uiinit() error {
@@ -66,6 +67,15 @@ func ui() {
msgloop()
}
+// we'll use SendMessage() here, which will do a thread switch, call the function immediately, and wait for it to return, so we don't have to worry about the garbage collector collecting data
+func uipost(w *Window, data interface{}) {
+ _sendMessage.Call(
+ uintptr(w.sysData.hwnd), // note: we pass this directly to the window
+ msgPost,
+ 0,
+ uintptr(unsafe.Pointer(&data)))
+}
+
var (
_dispatchMessage = user32.NewProc("DispatchMessageW")
_getActiveWindow = user32.NewProc("GetActiveWindow")
diff --git a/window.go b/window.go
index d8375d3..99ffedf 100644
--- a/window.go
+++ b/window.go
@@ -15,6 +15,11 @@ type Window struct {
// If Closing is nil, a default which rejects the close will be used.
Closing func() bool
+ // Posted is called when Post() is called with the given Window as an argument.
+ // It receives the data passed to Post() as an argument.
+ // If Posted is nil, a default handler which does nothing will be used.
+ Posted func(data interface{})
+
created bool
sysData *sysData
initTitle string
@@ -87,6 +92,10 @@ func (w *Window) Create(control Control) {
return false
}
}
+ w.sysData.post = w.Posted
+ if w.sysData.post == nil {
+ w.sysData.post = func(data interface{}) {}
+ }
err := w.sysData.make(nil)
if err != nil {
panic(fmt.Errorf("error opening window: %v", err))