diff --git a/redo/windows/GNUmakeinc.mk b/redo/windows/GNUmakeinc.mk index 325abaaf..269226f2 100644 --- a/redo/windows/GNUmakeinc.mk +++ b/redo/windows/GNUmakeinc.mk @@ -9,6 +9,7 @@ osCFILES = \ windows/control.c \ windows/debug.c \ windows/entry.c \ + windows/events.c \ windows/group.c \ windows/init.c \ windows/label.c \ diff --git a/redo/windows/control.c b/redo/windows/control.c index 859d4318..f5e2e75f 100644 --- a/redo/windows/control.c +++ b/redo/windows/control.c @@ -4,7 +4,6 @@ struct singleHWND { uiControl *c; HWND hwnd; - BOOL (*onWM_COMMAND)(uiControl *, WORD, LRESULT *); BOOL (*onWM_NOTIFY)(uiControl *, NMHDR *, LRESULT *); BOOL (*onWM_HSCROLL)(uiControl *, WORD, LRESULT *); void (*onDestroy)(void *); @@ -16,6 +15,7 @@ void osSingleDestroy(void *internal) struct singleHWND *s = (struct singleHWND *) internal; (*(s->onDestroy))(s->onDestroyData); + uiWindowsUnregisterWM_COMMANDHandler(s->hwnd); if (DestroyWindow(s->hwnd) == 0) logLastError("error destroying control in singleDestroy()"); uiFree(s); @@ -110,10 +110,6 @@ static LRESULT CALLBACK singleSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LRESULT lResult; switch (uMsg) { - case msgCOMMAND: - if ((*(s->onWM_COMMAND))(s->c, HIWORD(wParam), &lResult) != FALSE) - return lResult; - break; case msgNOTIFY: if ((*(s->onWM_NOTIFY))(s->c, (NMHDR *) lParam, &lResult) != FALSE) return lResult; @@ -145,7 +141,8 @@ void uiWindowsMakeControl(uiControl *c, uiWindowsMakeControlParams *p) utilWindow, NULL, p->hInstance, p->lpParam); if (s->hwnd == NULL) logLastError("error creating control in uiWindowsMakeControl()"); - s->onWM_COMMAND = p->onWM_COMMAND; + + uiWindowsRegisterWM_COMMANDHandler(s->hwnd, p->onWM_COMMAND, uiControl(c)); s->onWM_NOTIFY = p->onWM_NOTIFY; s->onWM_HSCROLL = p->onWM_HSCROLL; diff --git a/redo/windows/events.c b/redo/windows/events.c new file mode 100644 index 00000000..d7d9bc2c --- /dev/null +++ b/redo/windows/events.c @@ -0,0 +1,79 @@ +// 20 may 2015 +#include "uipriv_windows.h" + +// TODO switch to uthash + +struct commandHandler { + HWND hwnd; + BOOL (*handler)(uiControl *, WORD, LRESULT *); + uiControl *c; +}; + +struct notifyHandler { + HWND hwnd; + BOOL (*handler)(uiControl *, NMHDR *, LRESULT *); + uiControl *c; +}; + +struct hscrollHandler { + HWND hwnd; + BOOL (*handler)(uiControl *, WORD, LRESULT *); + uiControl *c; +}; + +struct ptrArray *commandHandlers = NULL; +struct ptrArray *notifyHandlers = NULL; +struct ptrArray *hscrollHandlers = NULL; + +void uiWindowsRegisterWM_COMMANDHandler(HWND hwnd, BOOL (*handler)(uiControl *, WORD, LRESULT *), uiControl *c) +{ + struct commandHandler *ch; + + ch = uiNew(struct commandHandler); + ch->hwnd = hwnd; + ch->handler = handler; + ch->c = c; + if (commandHandlers == NULL) + commandHandlers = newPtrArray(); + ptrArrayAppend(commandHandlers, ch); +} + +void uiWindowsUnregisterWM_COMMANDHandler(HWND hwnd) +{ + struct commandHandler *ch; + uintmax_t i; + + for (i = 0; i < commandHandlers->len; i++) { + ch = ptrArrayIndex(commandHandlers, struct commandHandler *, i); + if (ch->hwnd == hwnd) { + ptrArrayDelete(commandHandlers, i); + uiFree(ch); + if (commandHandlers->len == 0) { + ptrArrayDestroy(commandHandlers); + commandHandlers = NULL; + } + return; + } + } + complain("window handle %p not registered with a WM_COMMAND handler in uiWindowsUnregisterWM_COMMANDHandler()", hwnd); +} + +BOOL runWM_COMMAND(WPARAM wParam, LPARAM lParam, LRESULT *lResult) +{ + HWND control; + struct commandHandler *ch; + uintmax_t i; + + // bounce back to the control in question + // don't bounce back if to the utility window, in which case act as if the message was ignored + control = (HWND) lParam; + if (control != NULL && IsChild(utilWindow, control) == 0) { + for (i = 0; i < commandHandlers->len; i++) { + ch = ptrArrayIndex(commandHandlers, struct commandHandler *, i); + if (ch->hwnd == control) + return (*(ch->handler))(ch->c, HIWORD(wParam), lResult); + } + // not registered; fall out to return FALSE + } + return FALSE; +} diff --git a/redo/windows/parent.c b/redo/windows/parent.c index 0f29766a..5a510b78 100644 --- a/redo/windows/parent.c +++ b/redo/windows/parent.c @@ -111,14 +111,7 @@ BOOL handleParentMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LR switch (uMsg) { case WM_COMMAND: - // bounce back to the control in question - // except if to the initial parent, in which case act as if the message was ignored - control = (HWND) lParam; - if (control != NULL && IsChild(utilWindow, control) == 0) { - *lResult = SendMessageW(control, msgCOMMAND, wParam, lParam); - return TRUE; - } - break; + return runWM_COMMAND(wParam, lParam, lResult); case WM_NOTIFY: // same as WM_COMMAND control = nm->hwndFrom; diff --git a/redo/windows/uipriv_windows.h b/redo/windows/uipriv_windows.h index 4a976765..97de71b1 100644 --- a/redo/windows/uipriv_windows.h +++ b/redo/windows/uipriv_windows.h @@ -108,3 +108,9 @@ extern void uninitAlloc(void); // tab.c extern void tabEnterTabNavigation(HWND); extern void tabLeaveTabNavigation(HWND); + +// events.c +// TODO split the uiWindows ones to ui_windows.h +extern void uiWindowsRegisterWM_COMMANDHandler(HWND, BOOL (*)(uiControl *, WORD, LRESULT *), uiControl *); +extern void uiWindowsUnregisterWM_COMMANDHandler(HWND); +extern BOOL runWM_COMMAND(WPARAM, LPARAM, LRESULT *);