diff --git a/redo/windows/GNUmakeinc.mk b/redo/windows/GNUmakeinc.mk index ba7fb5ed..81331122 100644 --- a/redo/windows/GNUmakeinc.mk +++ b/redo/windows/GNUmakeinc.mk @@ -9,6 +9,7 @@ osCFILES = \ windows/control.c \ windows/datetimepicker.c \ windows/debug.c \ + windows/dialoghelper.c \ windows/entry.c \ windows/events.c \ windows/group.c \ diff --git a/redo/windows/dialoghelper.c b/redo/windows/dialoghelper.c new file mode 100644 index 00000000..584247c6 --- /dev/null +++ b/redo/windows/dialoghelper.c @@ -0,0 +1,110 @@ +// 22 may 2015 +#include "uipriv_windows.h" + +// see http://stackoverflow.com/questions/25494914/is-there-something-like-cdn-filecancel-analogous-to-cdn-fileok-for-getting-when#comment40420049_25494914 + +// TODO reconcile this with users being able to enable/disable windows + +struct dialogDisableWindow { + HWND hwnd; + uintmax_t n; + UT_hash_handle hh; +}; + +static struct dialogDisableWindow *windows = NULL; + +void dialogHelperRegisterWindow(HWND hwnd) +{ + struct dialogDisableWindow *d; + + HASH_FIND_PTR(windows, &hwnd, d); + if (d != NULL) + complain("window handle %p already register in dialogHelperRegisterWindow()", hwnd); + d = uiNew(struct dialogDisableWindow); + d->hwnd = hwnd; + HASH_ADD_PTR(windows, hwnd, d); +} + +void dialogHelperUnregisterWindow(HWND hwnd) +{ + struct dialogDisableWindow *d; + + HASH_FIND_PTR(windows, &hwnd, d); + if (d == NULL) + complain("window handle %p not registered in dialogHelperUnregisterWindow()", hwnd); + HASH_DEL(windows, d); + uiFree(d); +} + +static void dialogBegin(void) +{ + struct dialogDisableWindow *d; + + for (d = windows; d != NULL; d = d->hh.next) { + EnableWindow(d->hwnd, FALSE); + d->n++; + } +} + +static void dialogEnd(void) +{ + struct dialogDisableWindow *d; + + for (d = windows; d != NULL; d = d->hh.next) { + d->n--; + if (d->n == 0) + EnableWindow(d->hwnd, TRUE); + } +} + +#define dialogHelperClass L"libui_dialogHelperClass" + +static LRESULT CALLBACK dialogHelperWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) { + case WM_CREATE: + dialogBegin(); + break; + case WM_ENABLE: + if (wParam != (WPARAM) FALSE) // enabling + dialogEnd(); + break; + } + return DefWindowProcW(hwnd, uMsg, wParam, lParam); +} + +ATOM initDialogHelper(HICON hDefaultIcon, HCURSOR hDefaultCursor) +{ + WNDCLASSW wc; + + ZeroMemory(&wc, sizeof (WNDCLASSW)); + wc.lpszClassName = dialogHelperClass; + wc.lpfnWndProc = dialogHelperWndProc; + wc.hInstance = hInstance; + wc.hIcon = hDefaultIcon; + wc.hCursor = hDefaultCursor; + wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); + return RegisterClassW(&wc); +} + +uintptr_t beginDialogHelper(void) +{ + HWND hwnd; + + hwnd = CreateWindowExW(0, + dialogHelperClass, L"libui dialog helper", + WS_OVERLAPPEDWINDOW, + 0, 0, 100, 100, + NULL, NULL, hInstance, NULL); + if (hwnd == NULL) + logLastError("error creating dialog helper in beginDialogHelper()"); + return (uintptr_t) hwnd; +} + +void endDialog(uintptr_t handle) +{ + HWND hwnd = (HWND) handle; + + if (DestroyWindow(hwnd) == 0) + logLastError("error cleaning up after dialog helper in endDialogHelper()"); +} diff --git a/redo/windows/init.c b/redo/windows/init.c index 9009d953..9dc1604b 100644 --- a/redo/windows/init.c +++ b/redo/windows/init.c @@ -141,6 +141,9 @@ const char *uiInit(uiInitOptions *o) if (InitCommonControlsEx(&icc) == 0) return loadLastError("initializing Common Controls"); + if (initDialogHelper(hDefaultIcon, hDefaultCursor) == 0) + return loadLastError("initializing the dialog helper"); + return NULL; } diff --git a/redo/windows/uipriv_windows.h b/redo/windows/uipriv_windows.h index c7ad1a55..0cbf71b3 100644 --- a/redo/windows/uipriv_windows.h +++ b/redo/windows/uipriv_windows.h @@ -120,3 +120,10 @@ extern void uiWindowsUnregisterWM_HSCROLLHandler(HWND); extern BOOL runWM_COMMAND(WPARAM, LPARAM, LRESULT *); extern BOOL runWM_NOTIFY(WPARAM, LPARAM, LRESULT *); extern BOOL runWM_HSCROLL(WPARAM, LPARAM, LRESULT *); + +// dialoghelper.c +extern void dialogHelperRegisterWindow(HWND); +extern void dialogHelperUnregisterWindow(HWND); +extern ATOM initDialogHelper(HICON, HCURSOR); +extern uintptr_t beginDialogHelper(void); +extern void endDialog(uintptr_t); diff --git a/redo/windows/window.c b/redo/windows/window.c index ad6ce836..9f578fd4 100644 --- a/redo/windows/window.c +++ b/redo/windows/window.c @@ -97,6 +97,7 @@ static void windowDestroy(uiControl *c) if (w->menubar != NULL) freeMenubar(w->menubar); // and finally destroy ourselves + dialogHelperUnregisterWindow(w->hwnd); if (DestroyWindow(w->hwnd) == 0) logLastError("error destroying uiWindow in windowDestroy()"); uiFree(w); @@ -351,6 +352,8 @@ uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar) logLastError("error creating window in uiWindow()"); uiFree(wtitle); + dialogHelperRegisterWindow(w->hwnd); + if (hasMenubar) { w->menubar = makeMenubar(); if (SetMenu(w->hwnd, w->menubar) == 0)