diff options
| -rw-r--r-- | stdwndclass_windows.go | 4 | ||||
| -rw-r--r-- | sysdata.go | 5 | ||||
| -rw-r--r-- | test/main.go | 7 | ||||
| -rw-r--r-- | uitask.go | 8 | ||||
| -rw-r--r-- | uitask_windows.go | 10 | ||||
| -rw-r--r-- | window.go | 9 |
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() @@ -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()) } }() } @@ -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") @@ -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)) |
