From 9251e89359ce46d08c0924b09d48fedbdf2c95fb Mon Sep 17 00:00:00 2001 From: Jonas Kümmerlin Date: Sun, 31 May 2020 01:49:11 +0200 Subject: ALFApplication and multiple toplevels support --- alf/alftoplevel.cpp | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 143 insertions(+), 5 deletions(-) (limited to 'alf/alftoplevel.cpp') diff --git a/alf/alftoplevel.cpp b/alf/alftoplevel.cpp index 161a738..b9f2e7b 100644 --- a/alf/alftoplevel.cpp +++ b/alf/alftoplevel.cpp @@ -3,8 +3,11 @@ #define ALF_TOPLEVEL_FLAG_MODALEND ((DWORD)1) typedef struct { + HWND hwnd; ALFToplevelVTable *vtbl; void *closure; + ALFListHeader toplevelList; + ALFApplication *app; DWORD flags; LPARAM modalResult; ALFLayout layout; @@ -12,9 +15,17 @@ typedef struct { HFONT hMessageFont; } ALFToplevelPriv; +struct tagALFApplication { + ALFListHeader toplevelList; + ALFToplevelPriv *activeToplevel; + BOOL (*pretranslatemessage)(void *,MSG *); + void *pretranslatemessage_closure; +}; + struct ALFToplevel_CreateParams{ ALFToplevelVTable *vtbl; void *closure; + ALFApplication *app; }; static TCHAR _alf_toplevelClass[28] = {0}; @@ -22,8 +33,8 @@ static TCHAR _alf_toplevelClass[28] = {0}; static void ALF_InitializeToplevelPriv(HWND hwnd, ALFToplevelPriv *priv) { - (void)hwnd; - + priv->hwnd = hwnd; + ALF_ListInit(&priv->toplevelList); ALF_Layout_Init(&priv->layout); priv->layout.bgcolor = ALF_COLOR_SYS(COLOR_BTNFACE); } @@ -34,6 +45,10 @@ ALF_DestroyToplevelPriv(ALFToplevelPriv *priv) if (priv->vtbl && priv->vtbl->postdestroy) priv->vtbl->postdestroy(priv->closure); + if (priv->app && priv->app->activeToplevel == priv) + priv->app->activeToplevel = NULL; + + ALF_ListRemove(&priv->toplevelList); ALF_Layout_Clear(&priv->layout); if (priv->hMessageFont) @@ -166,6 +181,11 @@ ALF_Toplevel_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) priv->vtbl = params->vtbl; priv->closure = params->closure; + priv->app = params->app; + + if (priv->app) { + ALF_ListInsert(&priv->app->toplevelList, &priv->toplevelList); + } BOOL retval = TRUE; if (priv->vtbl && priv->vtbl->initialize) { @@ -195,6 +215,18 @@ ALF_Toplevel_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) return 0; } + if (msg == WM_ACTIVATE) { + if (wparam) { + if (priv->app) { + priv->app->activeToplevel = priv; + } + } else { + if (priv->app && priv->app->activeToplevel == priv) { + priv->app->activeToplevel = NULL; + } + } + } + if (msg == WM_ERASEBKGND) { return TRUE; // handled in WM_PAINT } @@ -350,6 +382,10 @@ ALF_Toplevel_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) } } + if (msg == ALF_WM_GETAPPLICATION) { + return (LRESULT)priv->app; + } + LRESULT ret = 0; if (ALF_Layout_HandleMessage(&priv->layout, hwnd, msg, wparam, lparam, &ret)) { // if the layout was changed, our current size might be too small @@ -397,7 +433,7 @@ ALF_UnregisterToplevelClass(void) } HWND -ALF_CreateToplevelWindow(DWORD exstyle, DWORD style, HWND hwndOwner, ALFToplevelVTable *vtbl, void *closure) +ALF_CreateToplevelWindow(DWORD exstyle, DWORD style, HWND hwndOwner, ALFApplication *app, ALFToplevelVTable *vtbl, void *closure) { #pragma pack(push, 1) struct { @@ -428,6 +464,7 @@ ALF_CreateToplevelWindow(DWORD exstyle, DWORD style, HWND hwndOwner, ALFToplevel struct ALFToplevel_CreateParams params; params.vtbl = vtbl; params.closure = closure; + params.app = app; return CreateDialogIndirectParam(ALF_HINSTANCE, &t.t, hwndOwner, ALF_Toplevel_DlgProc, (LPARAM)¶ms); } @@ -456,8 +493,8 @@ ALF_Toplevel_ShowModal(HWND toplevel) while (!(priv->flags & ALF_TOPLEVEL_FLAG_MODALEND)) { MSG msg; if (GetMessage(&msg, NULL, 0, 0)) { - // TODO: call app-level message filter - if (!ALF_Toplevel_PreTranslateMessage(toplevel, &msg)) { + if (!(priv->app && ALF_Application_PreTranslateMessage(priv->app, &msg, toplevel)) + && !ALF_Toplevel_PreTranslateMessage(toplevel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } @@ -518,3 +555,104 @@ ALF_Toplevel_ResizePx(HWND win, int pxwidth, int pxheight) SetWindowPos(win, NULL, 0, 0, pxwidth, pxheight, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER); } + +ALFApplication * +ALF_Toplevel_Application(HWND toplevel) +{ + return (ALFApplication *)SendMessage(toplevel, ALF_WM_GETAPPLICATION, 0, 0); +} + +ALFApplication * +ALF_CreateApplication(void) +{ + ALFApplication *app = ALF_New(ALFApplication, 1); + ALF_ListInit(&app->toplevelList); + + return app; +} + +void +ALF_Application_ProcessMessages(ALFApplication *app) +{ + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) { + PostQuitMessage((int)msg.wParam); + return; + } else { + if (!ALF_Application_PreTranslateMessage(app, &msg, NULL)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } +} + +void +ALF_Application_Run(ALFApplication *app) +{ + while (!ALF_ListIsEmpty(&app->toplevelList)) { + MSG msg; + if (GetMessage(&msg, NULL, 0, 0)) { + if (!ALF_Application_PreTranslateMessage(app, &msg, NULL)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } else { + PostQuitMessage((int)msg.wParam); + return; + } + } +} + +BOOL +ALF_Application_EnumToplevels(ALFApplication *app, WNDENUMPROC proc, LPARAM param) +{ + ALF_FOR_LIST(ALFToplevelPriv, toplevelList, &app->toplevelList, t) { + if (!proc(t->hwnd, param)) + return FALSE; + } + + return TRUE; +} + +HWND +ALF_Application_ActiveToplevel(ALFApplication *app) +{ + return app->activeToplevel->hwnd; +} + +void +ALF_Application_SetPreTranslateMessageHandler(ALFApplication *app, BOOL(*handler)(void *,MSG *), void *closure) +{ + app->pretranslatemessage = handler; + app->pretranslatemessage_closure = closure; +} + +BOOL +ALF_Application_PreTranslateMessage(ALFApplication *app, MSG *msg, HWND modalToplevel) +{ + return (app->pretranslatemessage && app->pretranslatemessage(app->pretranslatemessage_closure, msg)) + || (app->activeToplevel && app->activeToplevel->hwnd != modalToplevel && ALF_Toplevel_PreTranslateMessage(app->activeToplevel->hwnd, msg)); +} + +// TODO: implement modal stuff +/*void +ALF_Application_DisableWindowsForModal(ALFApplication *app, HWND skip); + +void +ALF_Application_ReenableWindowsForModal(ALFApplication *app, HWND skip);*/ + +void +ALF_DestroyApplication(ALFApplication *app) +{ + // don't use ALF_FOR_LIST here, since ALF_FOR_LIST can only handle destroying + // the current element. But the window might to anything in WM_DESTROY, + // including destroying various other windows. + while (!ALF_ListIsEmpty(&app->toplevelList)) { + HWND w = ALF_LIST_CONTAINER(ALFToplevelPriv, toplevelList, app->toplevelList.next)->hwnd; + DestroyWindow(w); + } + + ALF_Free(app); +} -- cgit v1.2.3