Migrated controls_windows.go to C.
This commit is contained in:
parent
8fee588a1d
commit
7e40e9fe28
|
@ -0,0 +1,71 @@
|
|||
/* 17 july 2014 */
|
||||
|
||||
#include "winapi_windows.h"
|
||||
|
||||
HWND newWidget(LPCWSTR class, DWORD style, DWORD extstyle)
|
||||
{
|
||||
HWND hwnd;
|
||||
|
||||
hwnd = CreateWindowExW(
|
||||
extstyle,
|
||||
class, L"",
|
||||
style | WS_CHILD | WS_VISIBLE,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
/*
|
||||
the following has the consequence of making the control message-only at first
|
||||
this shouldn't cause any problems... hopefully not
|
||||
but see the msgwndproc() for caveat info
|
||||
also don't use low control IDs as they will conflict with dialog boxes (IDCANCEL, etc.)
|
||||
*/
|
||||
msgwin, (HMENU) 100, hInstance, NULL);
|
||||
if (hwnd == NULL) {
|
||||
xpanic("error creating control", GetLastError());
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
void controlSetParent(HWND control, HWND parent)
|
||||
{
|
||||
if (SetParent(control, parent) == NULL)
|
||||
xpanic("error changing control parent", GetLastError());
|
||||
}
|
||||
|
||||
/*
|
||||
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
|
||||
*/
|
||||
LRESULT forwardCommand(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
HWND control = (HWND) lParam;
|
||||
|
||||
/* don't generate an event if the control (if there is one) is unparented (a child of the message-only window) */
|
||||
if (control != NULL && IsChild(msgwin, control) == 0)
|
||||
return SendMessageW(control, msgCOMMAND, wParam, lParam);
|
||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK buttonSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data)
|
||||
{
|
||||
switch (uMsg) {
|
||||
case msgCOMMAND:
|
||||
if (HIWORD(wParam) == BN_CLICKED) {
|
||||
buttonClicked(data);
|
||||
return 0;
|
||||
}
|
||||
return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
|
||||
case WM_NCDESTROY:
|
||||
if ((*fv_RemoveWindowSubclass)(hwnd, buttonSubProc, id) == FALSE)
|
||||
xpanic("error removing Button subclass (which was for its own event handler)", GetLastError());
|
||||
return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
|
||||
default:
|
||||
return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
xmissedmsg("Button", "buttonSubProc()", uMsg);
|
||||
return 0; /* unreached */
|
||||
}
|
||||
|
||||
void setButtonSubclass(HWND hwnd, void *data)
|
||||
{
|
||||
if ((*fv_SetWindowSubclass)(hwnd, buttonSubProc, 0, (DWORD_PTR) data) == FALSE)
|
||||
xpanic("error subclassing Button to give it its own event handler", GetLastError());
|
||||
}
|
|
@ -8,47 +8,27 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
// #include "winapi_windows.h"
|
||||
import "C"
|
||||
|
||||
type widgetbase struct {
|
||||
hwnd uintptr
|
||||
hwnd C.HWND
|
||||
}
|
||||
|
||||
var emptystr = syscall.StringToUTF16Ptr("")
|
||||
|
||||
func newWidget(class *uint16, style uintptr, extstyle uintptr) *widgetbase {
|
||||
hwnd, err := f_CreateWindowExW(
|
||||
extstyle,
|
||||
class, emptystr,
|
||||
style | c_WS_CHILD | c_WS_VISIBLE,
|
||||
c_CW_USEDEFAULT, c_CW_USEDEFAULT,
|
||||
// c_CW_USEDEFAULT, c_CW_USEDEFAULT,
|
||||
100,100,
|
||||
// the following has the consequence of making the control message-only at first
|
||||
// this shouldn't cause any problems... hopefully not
|
||||
// but see the msgwndproc() for caveat info
|
||||
// also don't use low control IDs as they will conflict with dialog boxes (IDCANCEL, etc.)
|
||||
msgwin, 100, hInstance, nil)
|
||||
if hwnd == hNULL {
|
||||
panic(fmt.Errorf("creating control of class %q failed: %v", class, err))
|
||||
}
|
||||
func newWidget(class C.LPCWSTR, style uintptr, extstyle uintptr) *widgetbase {
|
||||
return &widgetbase{
|
||||
hwnd: hwnd,
|
||||
hwnd: C.newWidget(class, style, extstyle),
|
||||
}
|
||||
}
|
||||
|
||||
// these few methods are embedded by all the various Controls since they all will do the same thing
|
||||
|
||||
func (w *widgetbase) unparent() {
|
||||
res, err := f_SetParent(w.hwnd, msgwin)
|
||||
if res == hNULL { // result type is HWND
|
||||
panic(fmt.Errorf("error unparenting control: %v", err))
|
||||
}
|
||||
C.controlSetParent(w.hwnd, C.msgwin)
|
||||
}
|
||||
|
||||
func (w *widgetbase) parent(win *window) {
|
||||
res, err := f_SetParent(w.hwnd, win.hwnd)
|
||||
if res == hNULL { // result type is HWND
|
||||
panic(fmt.Errorf("error parenting control: %v", err))
|
||||
}
|
||||
C.controlSetParent(w.hwnd, win.hwnd)
|
||||
}
|
||||
|
||||
// don't embed these as exported; let each Control decide if it should
|
||||
|
@ -57,7 +37,7 @@ func (w *widgetbase) text() *Request {
|
|||
c := make(chan interface{})
|
||||
return &Request{
|
||||
op: func() {
|
||||
c <- getWindowText(w.hwnd)
|
||||
c <- C.GoString(C.getWindowText(w.hwnd))
|
||||
},
|
||||
resp: c,
|
||||
}
|
||||
|
@ -67,47 +47,33 @@ func (w *widgetbase) settext(text string, results ...t_LRESULT) *Request {
|
|||
c := make(chan interface{})
|
||||
return &Request{
|
||||
op: func() {
|
||||
setWindowText(w.hwnd, text, append([]t_LRESULT{c_FALSE}, results...))
|
||||
C.setWindowText(w.hwnd, toUTF16(text))
|
||||
c <- struct{}{}
|
||||
},
|
||||
resp: c,
|
||||
}
|
||||
}
|
||||
|
||||
// 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")
|
||||
var buttonclass = toUTF16("BUTTON")
|
||||
|
||||
func newButton(text string) *Request {
|
||||
c := make(chan interface{})
|
||||
return &Request{
|
||||
op: func() {
|
||||
w := newWidget(buttonclass,
|
||||
c_BS_PUSHBUTTON | c_WS_TABSTOP,
|
||||
C.BS_PUSHBUTTON | C.WS_TABSTOP,
|
||||
0)
|
||||
setWindowText(w.hwnd, text, []t_LRESULT{c_FALSE})
|
||||
C.setWindowText(w.hwnd, toUTF16(text))
|
||||
b := &button{
|
||||
widgetbase: w,
|
||||
clicked: newEvent(),
|
||||
}
|
||||
res, err := f_SetWindowSubclass(w.hwnd, buttonsubprocptr, 0, t_DWORD_PTR(uintptr(unsafe.Pointer(b))))
|
||||
if res == c_FALSE {
|
||||
panic(fmt.Errorf("error subclassing Button to give it its own event handler: %v", err))
|
||||
}
|
||||
C.setButtonSubclass(w.hwnd, unsafe.Pointer(b))
|
||||
c <- b
|
||||
},
|
||||
resp: c,
|
||||
|
@ -140,24 +106,9 @@ func init() {
|
|||
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
|
||||
}
|
||||
return f_DefSubclassProc(hwnd, uMsg, wParam, lParam)
|
||||
case c_WM_NCDESTROY:
|
||||
res, err := f_RemoveWindowSubclass(b.hwnd, buttonsubprocptr, id)
|
||||
if res == c_FALSE {
|
||||
panic(fmt.Errorf("error removing Button subclass (which was for its own event handler): %v", err))
|
||||
}
|
||||
return f_DefSubclassProc(hwnd, uMsg, wParam, lParam)
|
||||
default:
|
||||
return f_DefSubclassProc(hwnd, uMsg, wParam, lParam)
|
||||
}
|
||||
panic(fmt.Errorf("Button message %d does not return a value (bug in buttonSubProc())", uMsg))
|
||||
//export buttonClicked
|
||||
func buttonClicked(data unsafe.Pointer) {
|
||||
b := (*button)(data)
|
||||
b.clicked.fire()
|
||||
println("button clicked")
|
||||
}
|
||||
|
|
|
@ -32,3 +32,9 @@ extern DWORD initCommonControls(LPCWSTR, char **);
|
|||
extern BOOL (*WINAPI fv_SetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
|
||||
extern BOOL (*WINAPI fv_RemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR);
|
||||
extern LRESULT (*WINAPI fv_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
/* controls_windows.c */
|
||||
extern HWND newWidget(LPCWSTR, DWORD, DWORD);
|
||||
extern void controlSetParent(HWND, HWND);
|
||||
extern LRESULT forwardCommand(HWND, UINT, WPARAM, LPARAM);
|
||||
extern void setButtonSubclass(HWND, void *);
|
||||
|
|
Loading…
Reference in New Issue