From 6a6ddc61f93718f94bbc47d65c681406ff9f1bd7 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Wed, 20 May 2015 22:46:50 -0400 Subject: [PATCH] Started a major overhaul of the control system on Windows. Events are now handled using registered handlers rather than having them be part of the singleHWND. This is needed for radio buttons. Right now, only WM_COMMAND has been modified as such. --- redo/windows/GNUmakeinc.mk | 1 + redo/windows/control.c | 9 ++-- redo/windows/events.c | 79 +++++++++++++++++++++++++++++++++++ redo/windows/parent.c | 9 +--- redo/windows/uipriv_windows.h | 6 +++ 5 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 redo/windows/events.c 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 *);