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 {
containerbase
hwnd C.HWND
nchildren int
}
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))
}
c.child = control
c.child.setParent(&controlParent{c.hwnd})
c.child.setParent(&controlParent{c})
return c
}
func (c *container) setParent(p *controlParent) {
C.controlSetParent(c.hwnd, p.hwnd)
func (c *container) setParent(hwnd C.HWND) {
C.controlSetParent(c.hwnd, hwnd)
}
// 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 {
hwnd C.HWND
c *container
}
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

View File

@ -57,7 +57,8 @@ func (l *label) settextlen(len C.LONG) {
}
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 {

View File

@ -25,6 +25,8 @@ static LRESULT CALLBACK tabSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l
return 0;
}
return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam);
case msgTabCurrentTabHasChildren:
return (LRESULT) tabTabHasChildren((void *) data, SendMessageW(hwnd, TCM_GETCURSEL, 0, 0));
case WM_NCDESTROY:
if ((*fv_RemoveWindowSubclass)(hwnd, tabSubProc, id) == FALSE)
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) {
c := newContainer(control)
c.setParent(&controlParent{t._hwnd})
c.setParent(t._hwnd)
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
if len(t.tabs) != 1 {
@ -55,6 +55,15 @@ func tabChanged(data unsafe.Pointer, new C.LRESULT) {
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 {
return t._hwnd
}

View File

@ -41,17 +41,19 @@ void uimsgloop(void)
if (wcscmp(classchk, areaWindowClass) == 0)
dodlgmessage = FALSE;
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)
tabEnterChildren(focus);
// TODO this goes into an infinite loop on a blank tab
if (dodlgmessage)
if (dodlgmessage) {
if (istab)
tabEnterChildren(focus);
idm = IsDialogMessageW(active, &msg);
if (istab)
tabLeaveChildren(focus);
if (idm != 0)
continue;
if (istab)
tabLeaveChildren(focus);
if (idm != 0)
continue;
}
}
TranslateMessage(&msg);
DispatchMessageW(&msg);

View File

@ -29,6 +29,7 @@ enum {
msgNOTIFY, // WM_NOTIFY proxy
msgAreaSizeChanged,
msgAreaRepaintAll,
msgTabCurrentTabHasChildren,
};
// 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 {
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
}