Fixed the infinite loop on Tab control dialog message bug(s) on the Windows backend.

This commit is contained in:
Pietro Gagliardi 2014-08-14 13:05:31 -04:00
parent 2c8bb7bc6d
commit acbe70b4e5
8 changed files with 34 additions and 17 deletions

View File

@ -14,6 +14,7 @@ import "C"
type container struct { type container struct {
containerbase containerbase
hwnd C.HWND hwnd C.HWND
nchildren int
} }
type sizing struct { type sizing struct {
@ -45,12 +46,12 @@ func newContainer(control Control) *container {
panic(fmt.Errorf("inconsistency: hwnd returned by CreateWindowEx() (%p) and hwnd stored in container (%p) differ", hwnd, c.hwnd)) panic(fmt.Errorf("inconsistency: hwnd returned by CreateWindowEx() (%p) and hwnd stored in container (%p) differ", hwnd, c.hwnd))
} }
c.child = control c.child = control
c.child.setParent(&controlParent{c.hwnd}) c.child.setParent(&controlParent{c})
return c return c
} }
func (c *container) setParent(p *controlParent) { func (c *container) setParent(hwnd C.HWND) {
C.controlSetParent(c.hwnd, p.hwnd) C.controlSetParent(c.hwnd, hwnd)
} }
// this is needed because Windows won't move/resize a child window for us // this is needed because Windows won't move/resize a child window for us

View File

@ -11,11 +11,12 @@ type controlPrivate interface {
} }
type controlParent struct { type controlParent struct {
hwnd C.HWND c *container
} }
func basesetParent(c controlPrivate, p *controlParent) { func basesetParent(c controlPrivate, p *controlParent) {
C.controlSetParent(c.hwnd(), p.hwnd) C.controlSetParent(c.hwnd(), p.c.hwnd)
p.c.nchildren++
} }
// don't specify basepreferredSize; it is custom on ALL controls // don't specify basepreferredSize; it is custom on ALL controls

View File

@ -57,7 +57,8 @@ func (l *label) settextlen(len C.LONG) {
} }
func (l *label) setParent(p *controlParent) { func (l *label) setParent(p *controlParent) {
basesetParent(l, p) C.controlSetParent(l.hwnd(), p.c.hwnd)
// don't increment p.c.nchildren here because Labels aren't tab stops
} }
func (l *label) allocate(x int, y int, width int, height int, d *sizing) []*allocation { func (l *label) allocate(x int, y int, width int, height int, d *sizing) []*allocation {

View File

@ -25,6 +25,8 @@ static LRESULT CALLBACK tabSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l
return 0; return 0;
} }
return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
case msgTabCurrentTabHasChildren:
return (LRESULT) tabTabHasChildren((void *) data, SendMessageW(hwnd, TCM_GETCURSEL, 0, 0));
case WM_NCDESTROY: case WM_NCDESTROY:
if ((*fv_RemoveWindowSubclass)(hwnd, tabSubProc, id) == FALSE) if ((*fv_RemoveWindowSubclass)(hwnd, tabSubProc, id) == FALSE)
xpanic("error removing Tab subclass (which was for its own event handler)", GetLastError()); xpanic("error removing Tab subclass (which was for its own event handler)", GetLastError());

View File

@ -34,7 +34,7 @@ func newTab() Tab {
func (t *tab) Append(name string, control Control) { func (t *tab) Append(name string, control Control) {
c := newContainer(control) c := newContainer(control)
c.setParent(&controlParent{t._hwnd}) c.setParent(t._hwnd)
t.tabs = append(t.tabs, c) t.tabs = append(t.tabs, c)
// initially hide tab 1..n controls; if we don't, they'll appear over other tabs, resulting in weird behavior // initially hide tab 1..n controls; if we don't, they'll appear over other tabs, resulting in weird behavior
if len(t.tabs) != 1 { if len(t.tabs) != 1 {
@ -55,6 +55,15 @@ func tabChanged(data unsafe.Pointer, new C.LRESULT) {
t.tabs[int(new)].show() t.tabs[int(new)].show()
} }
//export tabTabHasChildren
func tabTabHasChildren(data unsafe.Pointer, which C.LRESULT) C.BOOL {
t := (*tab)(data)
if t.tabs[int(which)].nchildren > 0 {
return C.TRUE
}
return C.FALSE
}
func (t *tab) hwnd() C.HWND { func (t *tab) hwnd() C.HWND {
return t._hwnd return t._hwnd
} }

View File

@ -41,17 +41,19 @@ void uimsgloop(void)
if (wcscmp(classchk, areaWindowClass) == 0) if (wcscmp(classchk, areaWindowClass) == 0)
dodlgmessage = FALSE; dodlgmessage = FALSE;
else if (wcscmp(classchk, WC_TABCONTROL) == 0) else if (wcscmp(classchk, WC_TABCONTROL) == 0)
istab = TRUE; // THIS BIT IS IMPORTANT
// if the current tab has no children, then there will be no children left in the dialog to tab to, and IsDialogMessageW() will loop forever
istab = (BOOL) SendMessageW(focus, msgTabCurrentTabHasChildren, 0, 0);
} }
if (istab) if (dodlgmessage) {
tabEnterChildren(focus); if (istab)
// TODO this goes into an infinite loop on a blank tab tabEnterChildren(focus);
if (dodlgmessage)
idm = IsDialogMessageW(active, &msg); idm = IsDialogMessageW(active, &msg);
if (istab) if (istab)
tabLeaveChildren(focus); tabLeaveChildren(focus);
if (idm != 0) if (idm != 0)
continue; continue;
}
} }
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessageW(&msg); DispatchMessageW(&msg);

View File

@ -29,6 +29,7 @@ enum {
msgNOTIFY, // WM_NOTIFY proxy msgNOTIFY, // WM_NOTIFY proxy
msgAreaSizeChanged, msgAreaSizeChanged,
msgAreaRepaintAll, msgAreaRepaintAll,
msgTabCurrentTabHasChildren,
}; };
// uitask_windows.c // uitask_windows.c

View File

@ -44,7 +44,7 @@ func newWindow(title string, width int, height int, control Control) *window {
if hresult != C.S_OK { if hresult != C.S_OK {
panic(fmt.Errorf("error setting tab background texture on Window; HRESULT: 0x%X", hresult)) panic(fmt.Errorf("error setting tab background texture on Window; HRESULT: 0x%X", hresult))
} }
w.container.setParent(&controlParent{w.hwnd}) w.container.setParent(w.hwnd)
return w return w
} }