summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-07-17 15:10:26 -0400
committerPietro Gagliardi <[email protected]>2014-07-17 15:10:26 -0400
commit19f7b2946a6198862f860b1f7c5798c0d66b8fc1 (patch)
treedcad78ffbde01eb9d4b952e15a33f6308eea8559
parent1a712d4064a646f366612139269d075db78d56cd (diff)
Laid down the framework for control events on Windows. The only problem left is that we need to use functions from comctl32.dll, so it's time to bring that blob of code back.
-rw-r--r--redo/common_windows.go10
-rw-r--r--redo/controls_windows.go45
-rw-r--r--redo/funcnames_windows.go1
-rw-r--r--redo/uitask_windows.go3
-rw-r--r--redo/window_windows.go3
-rw-r--r--redo/zwinconstgen.go2
6 files changed, 62 insertions, 2 deletions
diff --git a/redo/common_windows.go b/redo/common_windows.go
index d2cae60..30c0d75 100644
--- a/redo/common_windows.go
+++ b/redo/common_windows.go
@@ -46,3 +46,13 @@ func storelpParam(hwnd uintptr, lParam t_LPARAM) {
cs = (*s_CREATESTRUCTW)(unsafe.Pointer(uintptr(lParam)))
f_SetWindowLongPtrW(hwnd, c_GWLP_USERDATA, cs.lpCreateParams)
}
+
+func (w t_WPARAM) HIWORD() uint16 {
+ u := uintptr(w) & 0xFFFF0000
+ return uint16(u >> 16)
+}
+
+func (w t_WPARAM) LOWORD() uint16 {
+ u := uintptr(w) & 0x0000FFFF
+ return uint16(u)
+}
diff --git a/redo/controls_windows.go b/redo/controls_windows.go
index 3b73b48..dd4b8c9 100644
--- a/redo/controls_windows.go
+++ b/redo/controls_windows.go
@@ -5,6 +5,7 @@ package ui
import (
"fmt"
"syscall"
+ "unsafe"
)
type widgetbase struct {
@@ -73,8 +74,20 @@ func (w *widgetbase) settext(text string, results ...t_LRESULT) *Request {
}
}
+// all controls that have events receive the events themselves through subclasses
+// to do this, all windows (including the message-only window; see http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q104069) forward WM_COMMAND to each control with this function
+func forwardCommand(hwnd uintptr, uMsg t_UINT, wParam t_WPARAM, lParam t_LPARAM) t_LRESULT {
+ control := uintptr(lParam)
+ // don't generate an event if the control (if there is one) is unparented (a child of the message-only window)
+ if control != hNULL && f_IsChild(msgwin, control) == 0 {
+ return f_SendMessageW(control, msgCOMMAND, wParam, lParam)
+ }
+ return f_DefWindowProcW(hwnd, uMsg, wParam, lParam)
+}
+
type button struct {
*widgetbase
+ clicked *event
}
var buttonclass = syscall.StringToUTF16Ptr("BUTTON")
@@ -89,6 +102,7 @@ func newButton(text string) *Request {
setWindowText(w.hwnd, text, []t_LRESULT{c_FALSE})
c <- &button{
widgetbase: w,
+ clicked: newEvent(),
}
},
resp: c,
@@ -96,8 +110,14 @@ func newButton(text string) *Request {
}
func (b *button) OnClicked(e func(c Doer)) *Request {
- // TODO
- return nil
+ c := make(chan interface{})
+ return &Request{
+ op: func() {
+ b.clicked.set(e)
+ c <- struct{}{}
+ },
+ resp: c,
+ }
}
func (b *button) Text() *Request {
@@ -107,3 +127,24 @@ func (b *button) Text() *Request {
func (b *button) SetText(text string) *Request {
return b.settext(text)
}
+
+var buttonsubprocptr = syscall.NewCallback(buttonSubProc)
+
+func buttonSubProc(hwnd uintptr, uMsg t_UINT, wParam t_WPARAM, lParam t_LPARAM, id t_UINT_PTR, data t_DWORD_PTR) t_LRESULT {
+ b := (*button)(unsafe.Pointer(uintptr(data)))
+ switch uMsg {
+ case msgCOMMAND:
+ if wParam.HIWORD() == c_BN_CLICKED {
+ b.clicked.fire()
+ println("button clicked")
+ return 0
+ }
+ // TODO return
+ case c_WM_NCDESTROY:
+ // TODO remove
+ // TODO return
+ default:
+ // TODO return
+ }
+ panic(fmt.Errorf("Button message %d does not return a value (bug in buttonSubProc())", uMsg))
+}
diff --git a/redo/funcnames_windows.go b/redo/funcnames_windows.go
index 4a12430..005607f 100644
--- a/redo/funcnames_windows.go
+++ b/redo/funcnames_windows.go
@@ -38,3 +38,4 @@ package ui
// wfunc user32 GetDC uintptr uintptr
// wfunc gdi32 SelectObject uintptr uintptr uintptr
// wfunc user32 ReleaseDC uintptr uintptr uintptr
+// wfunc user32 IsChild uintptr uintptr uintptr,noerr
diff --git a/redo/uitask_windows.go b/redo/uitask_windows.go
index 6c5b974..8e8187a 100644
--- a/redo/uitask_windows.go
+++ b/redo/uitask_windows.go
@@ -11,6 +11,7 @@ import (
// global messages unique to everything
const (
msgRequest = c_WM_APP + 1 + iota // + 1 just to be safe
+ msgCOMMAND // WM_COMMAND proxy; see forwardCommand() in controls_windows.go
)
var msgwin uintptr
@@ -91,6 +92,8 @@ func makemsgwin() error {
func msgwinproc(hwnd uintptr, uMsg t_UINT, wParam t_WPARAM, lParam t_LPARAM) t_LRESULT {
switch uMsg {
+ case c_WM_COMMAND:
+ return forwardCommand(hwnd, uMsg, wParam, lParam)
case msgRequest:
req := (*Request)(unsafe.Pointer(uintptr(lParam)))
perform(req)
diff --git a/redo/window_windows.go b/redo/window_windows.go
index 9bf0b26..c58d028 100644
--- a/redo/window_windows.go
+++ b/redo/window_windows.go
@@ -160,6 +160,7 @@ func (w *window) OnClosing(e func(Doer) bool) *Request {
}
}
+// TODO msg -> uMsg
func windowWndProc(hwnd uintptr, msg t_UINT, wParam t_WPARAM, lParam t_LPARAM) t_LRESULT {
w := (*window)(unsafe.Pointer(f_GetWindowLongPtrW(hwnd, c_GWLP_USERDATA)))
if w == nil {
@@ -173,6 +174,8 @@ func windowWndProc(hwnd uintptr, msg t_UINT, wParam t_WPARAM, lParam t_LPARAM) t
return f_DefWindowProcW(hwnd, msg, wParam, lParam)
}
switch msg {
+ case c_WM_COMMAND:
+ return forwardCommand(hwnd, msg, wParam, lParam)
case c_WM_SIZE:
var r s_RECT
diff --git a/redo/zwinconstgen.go b/redo/zwinconstgen.go
index 28ff843..c0e2171 100644
--- a/redo/zwinconstgen.go
+++ b/redo/zwinconstgen.go
@@ -276,6 +276,8 @@ func main() {
fmt.Fprintf(buf, "type t_WPARAM %s\n", winName(reflect.TypeOf(C.WPARAM(0))))
fmt.Fprintf(buf, "type t_LPARAM %s\n", winName(reflect.TypeOf(C.LPARAM(0))))
fmt.Fprintf(buf, "type t_LRESULT %s\n", winName(reflect.TypeOf(C.LRESULT(0))))
+ fmt.Fprintf(buf, "type t_UINT_PTR %s\n", winName(reflect.TypeOf(C.UINT_PTR(0))))
+ fmt.Fprintf(buf, "type t_DWORD_PTR %s\n", winName(reflect.TypeOf(C.DWORD_PTR(0))))
// and one for GetMessageW()
fmt.Fprintf(buf, "type t_BOOL %s\n", winName(reflect.TypeOf(C.BOOL(0))))