diff options
| author | Jonas Kümmerlin <jonas@kuemmerlin.eu> | 2020-05-31 01:49:11 +0200 |
|---|---|---|
| committer | Jonas Kümmerlin <jonas@kuemmerlin.eu> | 2020-05-31 01:49:11 +0200 |
| commit | 9251e89359ce46d08c0924b09d48fedbdf2c95fb (patch) | |
| tree | 4adb0418223a07834f8e55a457c07ceda1bf29b3 /alf | |
| parent | 8d31086aed4aa91232cbaad9cf88d720e6329bcf (diff) | |
ALFApplication and multiple toplevels support
Diffstat (limited to 'alf')
| -rw-r--r-- | alf/alf.h | 51 | ||||
| -rw-r--r-- | alf/alflist.h | 4 | ||||
| -rw-r--r-- | alf/alftoplevel.cpp | 148 |
3 files changed, 195 insertions, 8 deletions
@@ -80,6 +80,7 @@ typedef struct { #define ALF_WM_SETMODALRESULT (ALF_WM__BASE + 7) #define ALF_WM_GETMODALRESULT (ALF_WM__BASE + 8) #define ALF_WM_GETDPI (ALF_WM__BASE + 9) +#define ALF_WM_GETAPPLICATION (ALF_WM__BASE + 10) #define ALF_WM_BACKGROUNDCHANGE (ALF_WM__BASE + 11) #define ALF_WM_APPLYSIZE (ALF_WM__BASE + 12) #define ALF_WM_SETBGCOLOR (ALF_WM__BASE + 13) @@ -301,10 +302,58 @@ ALF_FillRect(HDC dc, const RECT *rc, ALFColor color); void ALF_DestroyWidget(HWND win, WORD id); + +// application + +// an application is a container for multiple top-level windows +// NOTE: ALFApplication is not thread-safe. It must be accessed only from the +// thread that created it, and all toplevels associated with the application +// must live on that same thread. + +typedef struct tagALFApplication ALFApplication; + +ALFApplication * +ALF_CreateApplication(void); + +void +ALF_Application_ProcessMessages(ALFApplication *app); + +// continuously processes messages until a quit message is posted +// or all windows have been destroyed +void +ALF_Application_Run(ALFApplication *app); + +BOOL +ALF_Application_EnumToplevels(ALFApplication *app, WNDENUMPROC proc, LPARAM param); + +HWND +ALF_Application_ActiveToplevel(ALFApplication *app); + +void +ALF_Application_SetPreTranslateMessageHandler(ALFApplication *app, BOOL(*handler)(void *,MSG *), void *closure); + +BOOL +ALF_Application_PreTranslateMessage(ALFApplication *app, MSG *msg, HWND modalToplevel); + +// TODO: implement modal stuff +/*void +ALF_Application_DisableWindowsForModal(ALFApplication *app, HWND skip); + +void +ALF_Application_ReenableWindowsForModal(ALFApplication *app, HWND skip);*/ + +// also destroys all toplevels associated with the application +void +ALF_DestroyApplication(ALFApplication *app); + + // toplevel window 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); + +ALFApplication * +ALF_Toplevel_Application(HWND toplevel); void ALF_Toplevel_Resize(HWND win, int cptWidth, int cptHeight); diff --git a/alf/alflist.h b/alf/alflist.h index 7b4ca66..8bbfda8 100644 --- a/alf/alflist.h +++ b/alf/alflist.h @@ -38,8 +38,8 @@ ALF_ListRemove(ALFListHeader *member) { member->prev->next = member->next; member->next->prev = member->prev; - member->next = NULL; - member->prev = NULL; + member->next = member; + member->prev = member; } static inline void 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); +} |
